首先如果我们不考虑复杂度的话,直接主席树二分就能轻松解决了
但是3e5的数据范围会让的算法跑得很慢,而且常数也比较大
所以我们考虑换一个思路
假如我们从小到大把点按权值排序,然后开始用并查集合并,记录下合并时的位置的值,最左边的位置,以及所在块的权值
接着我们考虑把询问的权值从大到小排序,那么对于每一个询问,就可以把所有权值比他大的合并点都加进来
我们设询问的左端点l作为左边界时,右边界最小为minpos,右端点r作为右边界时,最大的左边界为maxpos;
这两个可以先统计一边贡献,对于之前的每次合并,我们在最左边的位置上修改最小值为合并时位置的值
那么我们查询时只需要查询l到maxpos所对应的最小值就可以了,
可以证明如果多了肯定不优,所以一定正确
别人的代码,我是真的不想写了
#include
using namespace std;
typedef long long lnt;
typedef long long ll;
typedef pair pii;
const lnt inf = 2e18;
const int N = 3e5 + 10;
int read() {
int x = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = (x << 1) + (x << 3) + c - '0' , c = getchar();
return x;
}
lnt readll() {
lnt x = 0;
char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = (x << 1) + (x << 3) + c - '0' , c = getchar();
return x;
}
void writeln(int x) {
if (!x) {
puts("0");
return;
}
int dg[20] , len = 0;
if (x < 0) x = -x , putchar('-');
while (x) {
dg[len++] = x % 10;
x /= 10;
}
while (len--) {
putchar(dg[len] + '0');
}
putchar('\n');
}
struct interval {
int l , r , maxn;
lnt sum;
inline bool operator < (const interval &A) const {
return sum > A.sum;
}
};
int n , m , d[N] , rnk[N];
lnt sum[N] , minm[N << 1] , maxn[N << 1];
lnt calc(int l,int r) {
return (sum[r] - sum[l-1]) * (r - l + 1);
}
void modify(int x,int l,int r,int pos,int v) {
if (l == r) {
minm[x] = v;
return;
}
int m = l + r >> 1 , z = x + ((m - l + 1) << 1);
if (pos <= m) {
modify(x + 1 , l , m , pos , v);
} else {
modify(z , m + 1 , r , pos , v);
}
minm[x] = min(minm[x + 1] , minm[z]);
}
int query(int x,int l,int r,int ql,int qr) {
if (ql <= l && r <= qr) {
return minm[x];
}
int m = l + r >> 1 , z = x + ((m - l + 1) << 1) , res = 1000000000;
if (ql <= m) res = min(res , query(x + 1 , l , m , ql , qr));
if (m < qr ) res = min(res , query(z , m + 1 , r , ql , qr));
return res;
}
void build(int x,int l,int r) {
minm[x] = 1000000000;
if (l == r) {
maxn[x] = d[l];
return;
}
int m = l + r >> 1 , z = x + ((m - l + 1) << 1);
build(x + 1 , l , m);
build(z , m + 1 , r);
maxn[x] = max(maxn[x + 1] , maxn[z]);
}
int querymax(int x,int l,int r,int ql,int qr) {
if (ql <= l && r <= qr) {
return maxn[x];
}
int m = l + r >> 1 , z = x + ((m - l + 1) << 1) , res = 0;
if (ql <= m) res = max(res , querymax(x + 1 , l , m , ql , qr));
if (m < qr ) res = max(res , querymax(z , m + 1 , r , ql , qr));
return res;
}
vector v;
set s;
struct Asktion {
int l , r , id;
lnt x;
inline bool operator < (const Asktion &A) const {
return x > A.x;
}
};
Asktion asks[N];
int res[N];
int getposl(int l,lnt x) {
int L = l , R = n , res = -1;
while (L <= R) {
int mid = L + R >> 1;
if (calc(l , mid) >= x) {
res = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
return res;
}
int getposr(int r,lnt x) {
int L = 1 , R = r , res = -1;
while (L <= R) {
int mid = L + R >> 1;
if (calc(mid , r) >= x) {
res = mid;
L = mid + 1;
} else {
R = mid - 1;
}
}
return res;
}
int main() {
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++) {
d[i] = read();
rnk[i] = i;
sum[i] = sum[i-1] + d[i];
}
build(1 , 1 , n);
sort(rnk + 1 , rnk + 1 + n , [](int a,int b) -> bool {return d[a] > d[b];});
s.insert(0);
s.insert(n + 1);
for (int i = 1; i <= n; i++) {
s.insert(rnk[i]);
set::iterator it = s.find(rnk[i]);
int pre = *(--it) + 1 , nxt = *(++++it) - 1;
v.push_back((interval) {
pre , nxt , d[rnk[i]] , 1ll * (nxt - pre + 1) * (sum[nxt] - sum[pre-1])
});
}
sort(v.begin() , v.end());
for (int i = 1; i <= m; i++) {
scanf("%d%d%lld",&asks[i].l,&asks[i].r,&asks[i].x);
asks[i].x = (asks[i].x + 1) >> 1;
asks[i].id = i;
}
sort(asks + 1 , asks + 1 + m);
int now = -1;
for (int i = 1; i <= m; i++) {
while (now + 1 < (int) v.size() && v[now + 1].sum >= asks[i].x) {
now++;
modify(1 , 1 , n , v[now].l , v[now].maxn);
}
int l = asks[i].l , r = asks[i].r , L = getposl(l , asks[i].x) , R = getposr(r , asks[i].x);
if (L == -1 || L > r) {
res[asks[i].id] = -1;
continue;
}
res[asks[i].id] = min( query(1 , 1 , n , l , R) , min(querymax(1 , 1 , n , l , L) , querymax(1 , 1 , n , R , r) ) );
}
for (int i = 1; i <= m; i++) printf("%d ",res[i]);
return 0;
}