线段树——讲课用——多标记问题
题目链接: https://www.luogu.org/problemnew/show/P2572
题解:
覆盖标记会对取反标记有什么影响?
取反标记作废
取反标记会对覆盖标记有什么影响?
若有覆盖标记,将覆盖标记取反,不打取反标记
若无覆盖标记,打上取反标记
所以一个节点只可能同时拥有一种标记,不需要考虑这两种标记同时下放的顺序问题
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 100001 int siz[N<<2]; int sum1[N<<2],sum0[N<<2]; int mx1[N<<2],mx0[N<<2]; int lcon1[N<<2],rcon1[N<<2],lcon0[N<<2],rcon0[N<<2]; int f[N<<2]; bool rev[N<<2]; int la,ans; char s[21]; int ll; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void up(int k) { int L=k<<1,R=k<<1|1; sum1[k]=sum1[L]+sum1[R]; sum0[k]=sum0[L]+sum0[R]; mx1[k]=max(mx1[L],mx1[R]); mx1[k]=max(mx1[k],rcon1[L]+lcon1[R]); mx0[k]=max(mx0[L],mx0[R]); mx0[k]=max(mx0[k],rcon0[L]+lcon0[R]); if(mx1[L]==siz[L]) lcon1[k]=siz[L]+lcon1[R]; else lcon1[k]=lcon1[L]; if(mx1[R]==siz[R]) rcon1[k]=siz[R]+rcon1[L]; else rcon1[k]=rcon1[R]; if(mx0[L]==siz[L]) lcon0[k]=siz[L]+lcon0[R]; else lcon0[k]=lcon0[L]; if(mx0[R]==siz[R]) rcon0[k]=siz[R]+rcon0[L]; else rcon0[k]=rcon0[R]; } void build(int k,int l,int r) { siz[k]=r-l+1; f[k]=-1; if(l==r) { read(la); if(la) sum1[k]=mx1[k]=lcon1[k]=rcon1[k]=1; else sum0[k]=mx0[k]=lcon0[k]=rcon0[k]=1; return; } int mid=l+r>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); up(k); } void down(int k) { int L=k<<1,R=k<<1|1; if(f[k]!=-1) { if(!f[k]) { sum0[L]=mx0[L]=lcon0[L]=rcon0[L]=siz[L]; sum1[L]=mx1[L]=lcon1[L]=rcon1[L]=0; sum0[R]=mx0[R]=lcon0[R]=rcon0[R]=siz[R]; sum1[R]=mx1[R]=lcon1[R]=rcon1[R]=0; } else { sum0[L]=mx0[L]=lcon0[L]=rcon0[L]=0; sum1[L]=mx1[L]=lcon1[L]=rcon1[L]=siz[L]; sum0[R]=mx0[R]=lcon0[R]=rcon0[R]=0; sum1[R]=mx1[R]=lcon1[R]=rcon1[R]=siz[R]; } rev[L]=rev[R]=false; f[L]=f[R]=f[k]; f[k]=-1; } if(rev[k]) { swap(sum0[L],sum1[L]); swap(mx0[L],mx1[L]); swap(lcon0[L],lcon1[L]); swap(rcon0[L],rcon1[L]); if(f[L]!=-1) f[L]=!f[L]; else rev[L]=!rev[L]; swap(sum0[R],sum1[R]); swap(mx0[R],mx1[R]); swap(lcon0[R],lcon1[R]); swap(rcon0[R],rcon1[R]); if(f[R]!=-1) f[R]=!f[R]; else rev[R]=!rev[R]; rev[k]=false; } } void change(int k,int l,int r,int a,int b,int opt) { if(l>=a && r<=b) { if(!opt) { sum0[k]=mx0[k]=lcon0[k]=rcon0[k]=siz[k]; sum1[k]=mx1[k]=lcon1[k]=rcon1[k]=0; } else { sum1[k]=mx1[k]=lcon1[k]=rcon1[k]=siz[k]; sum0[k]=mx0[k]=lcon0[k]=rcon0[k]=0; } f[k]=opt; rev[k]=false; return; } down(k); int mid=l+r>>1; if(a<=mid) change(k<<1,l,mid,a,b,opt); if(b>mid) change(k<<1|1,mid+1,r,a,b,opt); up(k); } void reversal(int k,int l,int r,int a,int b) { if(l>=a && r<=b) { swap(sum0[k],sum1[k]); swap(mx0[k],mx1[k]); swap(lcon0[k],lcon1[k]); swap(rcon0[k],rcon1[k]); if(f[k]!=-1) f[k]=!f[k]; else rev[k]=!rev[k]; return; } down(k); int mid=l+r>>1; if(a<=mid) reversal(k<<1,l,mid,a,b); if(b>mid) reversal(k<<1|1,mid+1,r,a,b); up(k); } void query_sum(int k,int l,int r,int a,int b) { if(l>=a && r<=b) { ans+=sum1[k]; return; } down(k); int mid=l+r>>1; if(a<=mid) query_sum(k<<1,l,mid,a,b); if(b>mid) query_sum(k<<1|1,mid+1,r,a,b); } void query_mx(int k,int l,int r,int a,int b,int &mx,int &mxl,int &mxr) { if(l>=a && r<=b) { mx=mx1[k]; mxl=lcon1[k]; mxr=rcon1[k]; return; } down(k); int mid=l+r>>1; int Lmx=0,Rmx=0,Lmxl=0,Rmxl=0,Lmxr=0,Rmxr=0; if(a<=mid) query_mx(k<<1,l,mid,a,b,Lmx,Lmxl,Lmxr); if(b>mid) query_mx(k<<1|1,mid+1,r,a,b,Rmx,Rmxl,Rmxr); mx=max(Lmx,Rmx); mx=max(Lmxr+Rmxl,mx); if(Lmxl==siz[k<<1]) mxl=Lmxl+Rmxl; else mxl=Lmxl; if(Rmxr==siz[k<<1|1]) mxr=Rmxr+Lmxr; else mxr=Rmxr; } void out(int x) { do s[++ll]=x%10+'0'; while(x/=10); while(ll) putchar(s[ll--]); putchar('\n'); } void init() { int n,m; read(n); read(m); build(1,1,n); int opt,a,b; int mx,mxl,mxr; while(m--) { read(opt); read(a); read(b); ++a; ++b; if(opt==0 || opt==1) change(1,1,n,a,b,opt); else if(opt==2) reversal(1,1,n,a,b); else if(opt==3) { ans=0; query_sum(1,1,n,a,b); out(ans); } else { query_mx(1,1,n,a,b,mx,mxl,mxr); out(mx); } } } int main() { init(); return 0; }