BZOJ4262 : Sum
最大值和最小值的问题是独立且相似的,考虑最大值:
考虑离线,设ask(i,l,r)为以1到i为右端点时左端点在区间[l,r]内的区间最大值的和。
从1到n枚举右端点,假设现在是i,那么可以通过单调栈求出最小的j使得[j,i]内a[i]是最大值。
然后左端点在[j,i]区间内的所有区间最大值都应当变为a[i],且所有答案应该加上本身的值。
通过线段树打标记维护,时间复杂度$O(n\log n)$。
对于线段树上每个节点,维护以下信息:
v : 区间内所有数的和
s : 历史上所有v的和
l : 区间长度
a,b,c,d : 标记,分别表示生效之后
v'=a*v+b*l
s'=c*v+d*l+s
#include<cstdio> #include<algorithm> #define N 262150 typedef long long ll; int n,m,i,j,l1,r1,l2,r2,a[N],q[N],t,cnt;ll t1,t2,ans[N]; struct Q{ int i,l,r,p,t; Q(){} Q(int _i,int _l,int _r,int _p,int _t){i=_i,l=_l,r=_r,p=_p,t=_t;} }b[N]; inline bool cmp(const Q&a,const Q&b){return a.i<b.i;} struct tag{ ll a,b,c,d; tag(){a=1,b=c=d=0;} tag(ll _a,ll _b,ll _c,ll _d){a=_a,b=_b,c=_c,d=_d;} inline bool ex(){return a!=1||b||c||d;} inline tag operator+(const tag&B){ return tag(a*B.a,b*B.a+B.b,a*B.c+c,d+b*B.c+B.d); } }tmp; struct Node{ll v,s;int l;tag t;}T[N]; inline void add1(int x,tag p){ T[x].s+=p.c*T[x].v+p.d*T[x].l; T[x].v=p.a*T[x].v+p.b*T[x].l; T[x].t=T[x].t+p; } inline void pb(int x){ if(T[x].t.ex()){ add1(x<<1,T[x].t); add1(x<<1|1,T[x].t); T[x].t=tag(); } } inline void up(int x){ T[x].v=T[x<<1].v+T[x<<1|1].v; T[x].s=T[x<<1].s+T[x<<1|1].s; } void build(int x,int a,int b){ T[x].v=T[x].s=0,T[x].l=b-a+1,T[x].t=tag(); if(a==b)return; int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); } void add(int x,int a,int b,int c,int d){ if(c<=a&&b<=d){add1(x,tmp);return;} pb(x); int mid=(a+b)>>1; if(c<=mid)add(x<<1,a,mid,c,d); if(d>mid)add(x<<1|1,mid+1,b,c,d); up(x); } ll ask(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return T[x].s; pb(x); int mid=(a+b)>>1;ll t=0; if(c<=mid)t=ask(x<<1,a,mid,c,d); if(d>mid)t+=ask(x<<1|1,mid+1,b,c,d); return up(x),t; } int main(){ for(scanf("%d",&m);i<m;i++){ scanf("%d%d%d%d",&l1,&r1,&l2,&r2); if(l2>1)b[++cnt]=Q(l2-1,l1,r1,i,-1); b[++cnt]=Q(r2,l1,r1,i,1); if(n<r1)n=r1; if(n<r2)n=r2; } std::sort(b+1,b+cnt+1,cmp); for(t1=1023,t2=1025,i=1;i<=n;i++,t1=t1*1023%1000000000,t2=t2*1025%1000000000)a[i]=t1^t2; for(build(1,1,n),i=j=1;i<=n;q[++t]=i++){ while(t&&a[q[t]]<a[i])t--; tmp=tag(0,a[i],0,0),add(1,1,n,q[t]+1,i),add1(1,tag(1,0,1,0)); while(j<=cnt&&b[j].i==i)ans[b[j].p]+=ask(1,1,n,b[j].l,b[j].r)*b[j].t,j++; } for(build(1,1,n),t=0,i=j=1;i<=n;q[++t]=i++){ while(t&&a[q[t]]>a[i])t--; tmp=tag(0,a[i],0,0),add(1,1,n,q[t]+1,i),add1(1,tag(1,0,1,0)); while(j<=cnt&&b[j].i==i)ans[b[j].p]-=ask(1,1,n,b[j].l,b[j].r)*b[j].t,j++; } for(i=0;i<m;i++)printf("%lld\n",ans[i]); return 0; }