analysis
Think first
O
(
n
m
)
O(nm)
How to do O(nm).
Sweep from left to right, and keep the current value and
x
0
x_0
x0 # take
max
\max
max.
Consider the positive solution:
set up
f
(
l
,
r
,
w
)
f(l,r,w)
f(l,r,w) is the initial
w
w
w. The working range is
(
l
,
r
)
(l,r)
(l,r) post closing value,
s
(
l
,
r
)
=
∑
i
=
l
r
a
i
s(l,r)=\sum_{i=l}^ra_i
s(l,r)=∑i=lrai.
Then there are:
f
(
l
,
r
,
w
)
=
min
(
f
(
l
,
r
,
i
n
f
)
,
w
+
s
(
l
,
r
)
)
f(l,r,w)=\min(f(l,r,inf),w+s(l,r))
f(l,r,w)=min(f(l,r,inf),w+s(l,r))
If you haven't met it all the time, it's obviously
w
+
s
(
l
,
r
)
w+s(l,r)
w+s(l,r).
Otherwise it will be with
f
(
l
,
r
,
i
n
f
)
f(l,r,inf)
f(l,r,inf) is the same. Consider the counter evidence: if the final result is different, the final top position must be different. There are two processes
A
,
B
A,B
A. B. the last top touching positions are
x
,
y
(
x
<
y
)
x,y(x<y)
x. Y (x < y) then
B
B
B must be
x
x
There is no top contact at x (otherwise)
A
,
B
A,B
A. B it's the same after that), so in
x
x
It's at x
A
>
B
A>B
A> B, then there must always be
A
≥
B
A\ge B
A≥B. But then came
y
y
y place
B
B
B touch the top and
A
A
A no, I have
A
<
B
A<B
A < B, contradiction.
After blocking, we can calculate the values of all intervals within the block
f
(
l
,
r
,
i
n
f
)
,
s
(
l
,
r
)
f(l,r,inf),s(l,r)
f(l,r,inf),s(l,r).
Note that if both eigenvalues of an interval do not exceed the other interval, it must be useless. So we can get rid of all useless intervals, leaving only
s
,
f
s,f
s. Some intervals of F inverse monotone.
If the two end points are in the block, we can find the bisection in these intervals in the block f + w , s f+w,s f+w,s is the dividing point where the size relationship changes, then the maximum value must be one of the intervals on both sides of the dividing point.
For the case of cross block, we use and
O
(
n
m
)
O(nm)
O(nm) violence is similar to the idea of sweeping one by one, trying to maintain the current maximum.
It can be divided into the following three cases:
- Start outside the left block and end inside the block.
- Start outside the left block and extend outside the right block.
- Start inside the block and extend outside the right block.
Using the idea similar to that in the block, all useful prefix intervals and suffix intervals can be processed for each block.
code
#include<bits/stdc++.h> using namespace std; #define ll long long #define ull unsigned long long #define debug(...) fprintf(stderr,__VA_ARGS__) #define ok debug("OK\n") inline ll read(){ ll x(0),f(1);char c=getchar(); while(!isdigit(c)){if(c=='-') f=-1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();} return x*f; } const int N=1e5+100; const int B=500; const int inf=1e9; int n,m,w; int bel[N],st[B],ed[B],tot; int a[N],lim[N],sum[N]; struct node{ int s,g; bool operator < (const node oth)const{ if(s!=oth.s) return s<oth.s; else return g<oth.g; } }; node pre[B][B],suf[B][B],c[B][N]; int num_pre[B],num_suf[B],num_c[B]; int s[B],g[B]; void init_block(){ w=sqrt(n); tot=(n+w-1)/w; for(int i=1;i<=n;i++) bel[i]=(i+w-1)/w; for(int i=1;i<=tot;i++) st[i]=(i-1)*w+1,ed[i]=min(n,i*w); return; } node tmp[N]; int calc(node *x,int num){ for(int i=1;i<=num;i++) tmp[i]=x[i]; sort(tmp+1,tmp+1+num); int top(0); for(int i=1;i<=num;i++){ while(top&&x[top].g<=tmp[i].g) --top; x[++top]=tmp[i]; } return top; } void solve(int k){ int num(0),num1(0),num2(0); for(int l=st[k];l<=ed[k];l++){ int now=inf,ss(0); for(int r=l;r<=ed[k];r++){ now=min(lim[r],now+a[r]);ss+=a[r]; c[k][++num]=(node){ss,now}; if(l==st[k]) pre[k][++num1]=(node){ss,now}; if(r==ed[k]) suf[k][++num2]=(node){ss,now}; if(l==st[k]&&r==ed[k]) s[k]=ss,g[k]=now; } } num_c[k]=calc(c[k],num); num_pre[k]=calc(pre[k],num1); num_suf[k]=calc(suf[k],num2); } void init(){ init_block(); for(int i=1;i<=tot;i++) solve(i); } int find(node *x,int num,int w){ int st=1,ed=num; while(st<ed){ int mid=(st+ed+1)>>1; if(x[mid].s+w<=x[mid].g) st=mid; else ed=mid-1; } int ans=min(x[st].s+w,x[st].g); if(st<num){ ++st; ans=max(ans,min(x[st].s+w,x[st].g)); } return ans; } signed main(){ #ifndef ONLINE_JUDGE //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); #endif n=read(); m=read(); for(int i=1;i<=n;i++) a[i]=read(),sum[i]=sum[i-1]+a[i]; for(int i=1;i<=n;i++) lim[i]=read(); init(); while(m--){ int l=read(),r=read(),w=read(); int x=bel[l],y=bel[r],cur=w,ans(0); if(x==y){ for(int i=l;i<=r;i++){ cur=max(w,min(lim[i],cur+a[i])); ans=max(ans,cur); } printf("%d\n",ans); } else{ for(int i=l;i<=ed[x];i++){ cur=max(w,min(lim[i],cur+a[i])); ans=max(ans,cur); } for(int i=x+1;i<y;i++){ ans=max(ans,find(c[i],num_c[i],w)); ans=max(ans,find(pre[i],num_pre[i],cur)); cur=max(w,max(min(cur+s[i],g[i]),find(suf[i],num_suf[i],w))); ans=max(ans,cur); } for(int i=st[y];i<=r;i++){ cur=max(w,min(lim[i],cur+a[i])); ans=max(ans,cur); } printf("%d\n",ans); } } return 0; } /* 58 14 5762 */