BZOJ4695 最假女选手
题目大意
维护一个序列,支持区间加,区间取$max,min$,区间求和,区间求最大最小值。
题解
区间取$max,min$必然要用到神奇的吉老师线段树,即维护区间最大值、最大值数量,次大值来剪枝。
即,当取$min$介于最大值和次大值之间时进行修改,否则暴力递归子树。
区间取$max$同理。
这道题还要套上区间加和区间求和,所以$pushdown$的时候还是比较麻烦的,注意要特殊处理最大值等于最小值或最大值等于严格次小值的情况。
复杂度据说是$O(N\log^2N)$吧,反正我不会证,
然而实际上跑的很快,虽然我的代码T掉了嘤嘤嘤
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define mid ((l+r)>>1) #define M 800010 #define INF 2000000000 using namespace std; int read(){ int nm=0,fh=1; int cw=getchar(); for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh; for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm*fh; } void write(LL x){if(x<0) putchar('-'),x=-x;if(x>9) write(x/10);putchar((int)(x%10+'0'));} LL p[M<<1],ans; int tg[M<<1],mx[M<<1],mn[M<<1],sx[M<<1],sn[M<<1],A[M],cx[M<<1],cn[M<<1]; int n,m,T,L[M<<1],R[M<<1],cnt,u[M],v[M],dt[M],t[M],Rt; inline void pushup(int x){ int ls=L[x],rs=R[x]; p[x]=p[ls]+p[rs]; if(mx[ls]>mx[rs]) mx[x]=mx[ls],cx[x]=cx[ls],sx[x]=max(mx[rs],sx[ls]); if(mx[ls]<mx[rs]) mx[x]=mx[rs],cx[x]=cx[rs],sx[x]=max(mx[ls],sx[rs]); if(mx[ls]==mx[rs]) mx[x]=mx[ls],cx[x]=cx[ls]+cx[rs],sx[x]=max(sx[ls],sx[rs]); if(mn[ls]<mn[rs]) mn[x]=mn[ls],cn[x]=cn[ls],sn[x]=min(mn[rs],sn[ls]); if(mn[ls]>mn[rs]) mn[x]=mn[rs],cn[x]=cn[rs],sn[x]=min(mn[ls],sn[rs]); if(mn[ls]==mn[rs]) mn[x]=mn[ls],cn[x]=cn[ls]+cn[rs],sn[x]=min(sn[ls],sn[rs]); } inline void inc(int x,LL len,int dt){tg[x]+=dt,mx[x]+=dt,mn[x]+=dt,sx[x]+=dt,sn[x]+=dt,p[x]+=len*((LL)dt);} inline void upmin(int num,int y){ if(mx[y]==mn[y]) mn[y]=num; if(mx[y]==sn[y]) sn[y]=num; p[y]+=(LL)(num-mx[y])*((LL)cx[y]),mx[y]=num; } inline void upmax(int num,int y){ if(mx[y]==mn[y]) mx[y]=num; if(mn[y]==sx[y]) sx[y]=num; p[y]+=(LL)(num-mn[y])*((LL)cn[y]),mn[y]=num; } inline void pushdown(int x,int l,int r){ int ls=L[x],rs=R[x]; LL lm=(mid-l+1),rm=(r-mid); if(tg[x]) inc(ls,lm,tg[x]),inc(rs,rm,tg[x]),tg[x]=0; if(mx[x]<mx[ls]) upmin(mx[x],ls); if(mx[x]<mx[rs]) upmin(mx[x],rs); if(mn[x]>mn[ls]) upmax(mn[x],ls); if(mn[x]>mn[rs]) upmax(mn[x],rs); } void build(int &x,int l,int r){ x=++cnt; if(l==r){p[x]=mx[x]=mn[x]=A[l],cx[x]=cn[x]=1;sx[x]=-INF,sn[x]=INF;return;} build(L[x],l,mid),build(R[x],mid+1,r),pushup(x); } LL qry(int x,int l,int r,int ls,int rs,int typ){ if(rs<l||r<ls){return typ==4?0:(typ==5?-INF:INF);} if(ls<=l&&r<=rs){return typ==4?p[x]:(typ==5?mx[x]:mn[x]);} pushdown(x,l,r); LL t1=qry(L[x],l,mid,ls,rs,typ); LL t2=qry(R[x],mid+1,r,ls,rs,typ); pushup(x); return typ==4?t1+t2:(typ==5?max(t1,t2):min(t1,t2)); } void add(int x,int l,int r,int ls,int rs,int dx){ if(r<ls||rs<l) return; if(ls<=l&&r<=rs){inc(x,r-l+1,dx);return;} pushdown(x,l,r),add(L[x],l,mid,ls,rs,dx); add(R[x],mid+1,r,ls,rs,dx),pushup(x); } void mdf(int x,int l,int r,int ls,int rs,int typ,int dx){ if(r<ls||rs<l||(typ==2&&mn[x]>=dx)||(typ==3&&mx[x]<=dx)) return; if(ls<=l&&r<=rs&&((typ==2&&sn[x]>dx)||(typ==3&&sx[x]<dx))){ if(typ==2) upmax(dx,x);else upmin(dx,x); return; } pushdown(x,l,r),mdf(L[x],l,mid,ls,rs,typ,dx); mdf(R[x],mid+1,r,ls,rs,typ,dx),pushup(x); } int main(){ n=read(); for(int i=1;i<=n;i++) A[i]=read(); build(Rt,1,n); for(int T=read(),tpe,ls,rs,dx;T;--T){ tpe=read(),ls=read(),rs=read(); if(tpe>3) ans=qry(Rt,1,n,ls,rs,tpe),write(ans),putchar('\n'); else if(tpe>1) dx=read(),mdf(Rt,1,n,ls,rs,tpe,dx); else dx=read(),add(Rt,1,n,ls,rs,dx); } return 0; }