bzoj2122: 工作评估
Description
利用空闲时间,BX希望外出工作,工作开始之前,公司就会给BX一个评估值X0,之后每天BX的评估值都是根据上一
天的评估值和当天公司的运行状况得出,即Xi=Xi-1+Di,但是每天的评估值有一个上限,也就是说完整的评估公式
因该是Xi=min{Xi-1+Di,Li}。现在BX已经知道了该公司对自己的初始评估值X0、公司每天的运行状况Di、每天的评
估上限Li,他的空闲时间是从第A天到第B天,他希望找到一段时间i,j (A≤i≤j≤B),使得从第i天开始工作,到
第j天结束后的评估值最大。当然如果任意一段时间的工作得到评估值都<初始评估值X0,BX可以选择不工作,从而
得到最大的评估值。
Input
输入的第一行包含两个整数N、M,分别表示总共工作天数和询问数。
第二行N个数,表示Di。第三行N个数,表示Li。
以下M行,每行3个数A、B、X0,表示一次询问。
Output
M行,每行输出一个整数,表示评估的最大值
Sample Input
6 3
-6 5 3 2 -3 4
8 10 8 1 9 9
1 3 9
2 6 3
3 4 0
Sample Output
10
8
3
【数据规模】
对于100%数据,满足N,M<50001,|Di|<10001,0≤Li<1000000001
分析
分块好题。
首先需要知道两个结论,设
f
(
l
,
r
,
x
0
)
f(l,r,x_0)
f(l,r,x0)表示以
x
0
x_0
x0为初始评估值从
l
l
l走到
r
r
r的最终评估值。
结论1:若 a ≥ b a\ge b a≥b,则 f ( l , r , a ) ≥ f ( l , r , b ) f(l,r,a) \ge f(l,r,b) f(l,r,a)≥f(l,r,b)
结论2:设 G ( l , r ) = f ( l , r , i n f ) , S ( l , r ) = ∑ i = l r d i G(l,r)=f(l,r,inf),S(l,r)=\sum_{i=l}^{r} d_i G(l,r)=f(l,r,inf),S(l,r)=∑i=lrdi有 f ( l , r , x 0 ) = min { G ( l , r ) , S ( l , r ) + x 0 } f (l,r,x_0)=\min\{G(l,r), S(l,r)+x_0\} f(l,r,x0)=min{G(l,r),S(l,r)+x0}
结论1是显然的,对于结论2,如果在某一次被限制 l i l_i li卡住了,那么答案显然就是 G ( l , r ) G(l,r) G(l,r),否则的话如果一次都没有被卡住,答案就是 S ( l , r ) + x 0 S(l,r)+x_0 S(l,r)+x0,再由结论1可得, G ( l , r ) ≥ S ( l , r ) + x 0 G(l,r)\ge S(l,r)+x_0 G(l,r)≥S(l,r)+x0(没有卡住),所以答案直接取 min \min min
考虑分块,采用块内快外分开计算贡献的方法。
块内
如果我们已经处理除了任意一对
(
l
,
r
)
(l,r)
(l,r)的
G
(
l
,
r
)
,
S
(
l
,
r
)
G(l,r),S(l,r)
G(l,r),S(l,r),考虑怎么快速求出答案。
一个显然的事情是,如果
G
(
l
,
r
)
≥
G
(
l
1
,
r
1
)
∧
S
(
l
,
r
)
≥
S
(
l
1
,
r
1
)
G(l,r)\ge G(l_1,r_1)\land S(l,r)\ge S(l_1,r_1)
G(l,r)≥G(l1,r1)∧S(l,r)≥S(l1,r1),那么可以直接舍去
l
1
,
r
1
l_1,r_1
l1,r1
这样我们得到了一个
G
i
G_i
Gi递增,
S
i
S_i
Si递减的序列,希望求出
max
i
min
{
G
i
,
S
i
+
x
0
}
\max_i\min \{G_i,S_i+x_0\}
maximin{Gi,Si+x0}
显然可以二分求最大值。
块外
不完整块可以暴力碾过去。
对于一个完整块,有几种选项。
1.从本块开始,从本块结束
2.从本块开始,走到块尾
3.从上一块走过来,从本块结束
4.从上一块走过来,走到块尾
5.不走这一块
于是预处理块内答案,每个位置走到块尾,从块头走到每个位置的 G ( l , r ) , S ( l , r ) G(l,r),S(l,r) G(l,r),S(l,r),用二分的方法求 1 , 2 , 3 1,2,3 1,2,3的答案, 4 4 4直接走过去, 5 5 5用开始的答案更新即可。
代码
#include<bits/stdc++.h>
const int M = 250, N = 5e4 + 5;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
struct O {
int g, s;
O(int _g = 0, int _s = 0) : g(_g), s(_s) {}
}o[N], v[M][N], pr[M][M], sf[M][M];
bool cmp(O a, O b) {return a.g == b.g ? a.s < b.s : a.g < b.g;}
int to, tp, st[N], b[N], l[N], r[N], d[N], li[N], s[N], f[M][M][M];
int S(int l, int r) {return s[r] - s[l - 1];}
int G(int L, int R) {return f[b[L]][L - l[b[L]]][R - l[b[L]]];}
int cn(int a, int b) {return a < b ? a : b;}
int cm(int a, int b) {return a > b ? a : b;}
void Up(int &a, int b) {a < b ? a = b : 0;}
void Cal(O *f) {
std::sort(o + 1, o + to + 1, cmp);
tp = 0;
for(int i = 1;i <= to; ++i) {
for(;tp && o[i].s >= o[st[tp]].s;) --tp;
st[++tp] = i;
}
f[0].s = tp; for(int i = 1;i <= tp; ++i) f[i] = o[st[i]];
}
void Pre(int x) {
for(int L = l[x]; L <= r[x]; ++L) {
int st = 0x3f3f3f3f;
for(int R = L; R <= r[x]; ++R)
st = cn(st + d[R], li[R]), f[x][L - l[x]][R - l[x]] = st;
}
to = 0;
for(int L = l[x]; L <= r[x]; ++L)
for(int R = L; R <= r[x]; ++R)
o[++to] = O(G(L, R), S(L, R));
Cal(v[x]);
to = 0;
for(int R = l[x]; R <= r[x]; ++R)
o[++to] = O(G(l[x], R), S(l[x], R));
Cal(pr[x]);
to = 0;
for(int L = l[x]; L <= r[x]; ++L)
o[++to] = O(G(L, r[x]), S(L, r[x]));
Cal(sf[x]);
}
O Move(int L, int R, int cr, int st) {
int r = cr;
for(int u = L; u <= R; ++u)
cr = cn(cm(cr, st) + d[u], li[u]), Up(r, cr);
return O(cr, r);
}
int Go(O *f, int st) {
int L = 1, R = f[0].s;
for(;L + 1 < R; ) {
int m = L + R >> 1;
f[m].g > f[m].s + st ? R = m : L = m;
}
int r = cn(f[L].g, f[L].s + st); ++L;
if(L <= f[0].s) Up(r, cn(f[L].g, f[L].s + st));
return r;
}
int Work(int L, int R, int st) {
if(b[L] == b[R]) return Move(L, R, st, st).s;
O x = Move(L, r[b[L]], st, st); int cr = cm(x.g, st), A = x.s;
for(int u = b[L] + 1; u < b[R]; ++u) {
Up(A, Go(pr[u], cr)); //上一块接着走,在这一块停下。
Up(A, Go(v[u], st)); //这一块重新走,在这一块停下。
cr = cn(G(l[u], r[u]), S(l[u], r[u]) + cr); //暴力走过这一块。
Up(cr, Go(sf[u], st));//这一块重新走,不停下
Up(cr, st); //不走这一块
}
return cm(A, Move(l[b[R]], R, cr, st).s);
}
int main() {
int n = ri(), m = ri(), B = sqrt(n);
for(int i = 1;i <= n; ++i) s[i] = s[i - 1] + (d[i] = ri());
for(int i = 1;i <= n; ++i) li[i] = ri();
for(int i = 1;i <= n; ++i) {
b[i] = (i - 1) / B + 1; r[b[i]] = i;
!l[b[i]] ? l[b[i]] = i : 0;
}
for(int i = 1;i <= b[n]; ++i) Pre(i);
for(;m--;) {
int L = ri(), R = ri(), st = ri();
printf("%d\n", Work(L, R, st));
}
return 0;
}