题解:
从头到尾只会写暴力。
首先要想到一个结论:
设
f
i
,
j
,
x
f_{i,j,x}
fi,j,x表示一开始是x,走i到j这一段后的愉悦度。
显然有:
若x1<=x2,则
f
i
,
j
,
x
1
<
=
f
i
,
j
,
x
2
f_{i,j,x1}<=f_{i,j,x2}
fi,j,x1<=fi,j,x2
还有 f i , j , x = m i n ( s i , j , f i , j , ∞ ) f_{i,j,x}=min(s_{i,j},f_{i,j,∞}) fi,j,x=min(si,j,fi,j,∞)
设 g i , j = f i , j , ∞ g_{i,j}=f_{i,j,∞} gi,j=fi,j,∞
然后看数据范围就可以考虑分块了。
对于一个块内的子区间,考虑按s,g排序,把肯定不是答案的去掉,然后对于一组询问就二分。
如果跨块,其实相当于维护一个最大值,搞搞每个块的开头和结尾就行了。
Code:
#include<cstdio>
#include<algorithm>
#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) > (b) ? (a) : (b))
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int N = 4e4 + 5, M = 150;
int n, q, x, y, z, d[N], L[N], s[N];
int bl[N], l[N], r[N];
int f[M + 5][M + 5];
struct Nod {
int s, g;
Nod() {}
Nod(int _s, int _g) {s = _s, g = _g;}
};
int cmp(Nod a, Nod b) {
if(a.s > b.s) return 1;
if(a.s < b.s) return 0;
return a.g > b.g;
}
struct nod {
Nod a[M * M + 5], b[M + 5], c[M + 5];
int a0, b0, c0, h;
void gg(Nod *a, int &a0) {
sort(a + 1, a + a0 + 1, cmp); int A = a0; a0 = 0;
fo(i, 1, A) if(!a0 || a[a0].g < a[i].g) a[++ a0] = a[i];
}
void B(int l, int r) {
fo(i, l, r) {
f[i - l][i - l] = L[i];
fo(j, i + 1, r) f[i - l][j - l] = min(L[j], max(f[i - l][j - l - 1], z) + d[j]);
}
fo(i, l, r) fo(j, i, r) {
Nod p = Nod(s[j] - s[i - 1], f[i - l][j - l]);
a[++ a0] = p; if(i == l) b[++ b0] = p; if(j == r) c[++ c0] = p;
}
h = f[0][r - l]; gg(a, a0); gg(b, b0); gg(c, c0);
}
int fi(Nod *a, int a0, int z) {
int A = 0;
for(int l = 1, r = a0; l <= r; ) {
int m = l + r >> 1;
if(a[m].s + z >= a[m].g) A = m, l = m + 1; else r = m - 1;
}
return max((!A ? 0 : a[A].g), (A == a0 ? 0 : a[A + 1].s + z));
}
} a[N / M + 5];
int main() {
freopen("park.in", "r", stdin);
freopen("park.out", "w", stdout);
scanf("%d %d", &n, &q);
fo(i, 1, n) scanf("%d", &d[i]), s[i] = s[i - 1] + d[i];
fo(i, 1, n) scanf("%d", &L[i]);
fo(i, 1, n) {
bl[i] = bl[i - 1];
if((i % M) == 1) r[bl[i] ++] = i - 1, l[bl[i]] = i;
} r[bl[n]] = n;
fo(i, 1, bl[n]) a[i].B(l[i], r[i]);
fo(ii, 1, q) {
scanf("%d %d %d", &x, &y, &z);
int ans = z;
if(bl[x] == bl[y]) {
int v = z;
fo(i, x, y) v = min(max(v, z) + d[i], L[i]), ans = max(ans, v);
printf("%d\n", ans);
continue;
}
int v = z;
fo(i, x, r[bl[x]]) v = min(max(v, z) + d[i], L[i]), ans = max(ans, v);
fo(i, bl[x] + 1, bl[y] - 1) {
int V = a[i].fi(a[i].a, a[i].a0, z); ans = max(ans, V);
V = a[i].fi(a[i].b, a[i].b0, v); ans = max(ans, V);
v = min(s[r[i]] - s[l[i] - 1] + v, a[i].h);
V = a[i].fi(a[i].c, a[i].c0, z); v = max(v, V);
}
fo(i, l[bl[y]], y) v = min(max(v, z) + d[i], L[i]), ans = max(ans, v);
printf("%d\n", ans);
}
}