1<=n,m<=3e5
题解:
O(nlog2n)O(n log^2 n)O(nlog2n)的方法很好想。
一个log主要是找性质。
首先思考一个区间[l,r]
如果a[l-1]<=max(l,r),则可以扩展到[l-1,r]
右端同理
这样的话有用的区间就被缩成了O(n)个,就是每个点开始往左往右一直走直到大于,也就是笛卡尔树。
现在假设查询[l,r]
考虑分成三种区间。
1.x=l的
2.y=r的
3.x>l && y<r的
前两种可以直接二分查询。
第三种看上去还是个三维偏序
假设第1、2问搞出的区间是
[l,tl]和[tr,r]
则只用查询y∈[tl…r]或x∈[x…tr]的区间就好了(都要查)
只证明第一个:
假设是区间[x,y],y一定要>=tl,不然由第一位没解得。
那么为什么不用管x<l的情况呢,
首先当x<l时,value(x,y)一定>=z(因为value(l,tl)>=z,[l…tl]∈[x…y])
其次这个区间一定是能扩展就扩展。所以有max(x,y)==max(l,y)
第二个同理,所以随便写个二维偏序的数据结构即可。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 3e5 + 5;
int n, m, x, y; ll z;
int a[N], d[N];
int g[19][N];
int cmp(int x, int y) {
if(a[x] == a[y]) return x < y;
return a[x] < a[y];
}
int f[N], mi[N], mx[N];
int F(int x) { return f[x] == x ? x : (f[x] = F(f[x]));}
void bin(int x, int y) {
if(F(x) != F(y)) {
x = f[x], y = f[y];
mi[y] = min(mi[y], mi[x]);
mx[y] = max(mx[y], mx[x]);
f[x] = y;
}
}
struct P {
int x, y, v;
ll z;
} e[N]; int e0;
int query(int x, int y) {
if(!x || !y) return 1e9;
int l = log2(y - x + 1);
return max(g[l][x], g[l][y - (1 << l) + 1]);
}
ll s[N];
ll calc(int x, int y) { return (s[y] - s[x - 1]) * (y - x + 1) * 2; }
int cmpe(P x, P y) {
return x.z > y.z;
}
struct tree {
int l, r, v;
} t[N * 40];
int g1[N], g2[N], tt;
int pl, pr, px;
#define i0 t[i].l
#define i1 t[i].r
void add(int &i, int x, int y) {
if(y < pl || x > pr) return;
t[++ tt] = t[i]; i = tt;
if(x == y) {
t[i].v = min(t[i].v, px);
return;
}
int m = x + y >> 1;
add(i0, x, m); add(i1, m + 1, y);
t[i].v = min(t[i0].v, t[i1].v);
}
void ft(int i, int x, int y) {
if(y < pl || x > pr || !i) return;
if(x >= pl && y <= pr) {
px = min(px, t[i].v);
return;
}
int m = x + y >> 1;
ft(i0, x, m); ft(i1, m + 1, y);
}
int main() {
freopen("duliu.in", "r", stdin);
freopen("duliu.out", "w", stdout);
scanf("%d %d", &n, &m);
fo(i, 1, n) scanf("%d", &a[i]);
fo(i, 1, n) g[0][i] = a[i];
fo(j, 1, 18) fo(i, 1, n) {
g[j][i] = g[j - 1][i];
if(i + (1 << j - 1) <= n) g[j][i] = max(g[j][i], g[j - 1][i + (1 << j - 1)]);
}
fo(i, 1, n) s[i] = s[i - 1] + a[i];
fo(i, 1, n) d[i] = i;
sort(d + 1, d + n + 1, cmp);
fo(i, 1, n) f[i] = mi[i] = mx[i] = i;
fo(i, 1, n) {
int x = d[i];
if(x > 1 && a[x - 1] <= a[x]) bin(x - 1, x);
if(x < n && a[x + 1] <= a[x]) bin(x + 1, x);
e[++ e0].x = mi[F(x)];
e[e0].y = mx[F(x)];
}
fo(i, 1, e0) {
e[i].z = calc(e[i].x, e[i].y);
e[i].v = query(e[i].x, e[i].y);
}
sort(e + 1, e + e0 + 1, cmpe);
t[0].v = 1e9;
fo(i, 1, e0) {
g1[i] = g1[i - 1];
g2[i] = g2[i - 1];
pl = pr = e[i].x; px = e[i].v;
add(g1[i], 1, n);
pl = pr = e[i].y;
add(g2[i], 1, n);
}
fo(i, 1, m) {
scanf("%d %d %lld", &x, &y, &z);
int as1 = 0;
for(int l = x, r = y; l <= r; ) {
int mi = l + r >> 1;
if(calc(x, mi) >= z) as1 = mi, r = mi - 1; else l = mi + 1;
}
int as2 = 0;
for(int l = x, r = y; l <= r; ) {
int mi = l + r >> 1;
if(calc(mi, y) >= z) as2 = mi, l = mi + 1; else r = mi - 1;
}
int as3 = 0;
for(int l = 1, r = e0; l <= r; ) {
int mi = l + r >> 1;
if(e[mi].z >= z) as3 = mi, l = mi + 1; else r = mi - 1;
}
px = min(query(x, as1), query(as2, y));
if(as1) {
pl = as1, pr = y;
ft(g2[as3], 1, n);
}
if(as2) {
pl = x, pr = as2;
ft(g1[as3], 1, n);
}
pp("%d\n", px > 1e7 ? -1 : px);
}
}