BZOJ1858 [Scoi2010]序列操作 线段树
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1858
题意概括
lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作:0 a b把[a,b]区间内的所有数全变成 0,1 a b把[a,b]区间内的所有数全变成1,2 a b 把[a,b]区间内的所有数全部取反,也就是说把所有的0变成1,把所有的1变成0,3 a b询问[a,b]区间内总共 有多少个1,4 a b询问[a,b]区间内最多有多少个连续的1,对于每一种询问操作,lxhgww都需要给出回答
题解
是一题暴力的线段树!
总共除了1的总个数之外,还要维护6个量,分别是(当前区间内)从左开始连续的0的个数,从又开始连续的0的个数,区间内最长的连续的0的个数;同理,1也有3个。这题多打几个子程序是缩减代码量的好方法,这样便于查找错误。这题真的拼仔细!
代码
#include <cstring> #include <cstdio> int n,m,ra[101000],op,a,b; int max2(int a,int b){return a>b?a:b;} int max3(int a,int b,int c){return max2(max2(a,b),c);} struct Segtree{ int tot,add,t100,t101,t110,t000,t001,t010,le,ri,si; void set(int l,int r){ tot=t100=t101=t110=t000=t001=t010=0; add=-1,le=l,ri=r,si=ri-le+1; } }t[101000*4]; void swap(int &a,int &b){ int c=a;a=b,b=c; } void pushup(int rt){ int ls=rt*2,rs=rt*2+1; t[rt].tot=t[ls].tot+t[rs].tot; t[rt].t110=t[ls].t110; if (t[ls].t110==t[ls].si) t[rt].t110+=t[rs].t110; t[rt].t101=t[rs].t101; if (t[rs].t101==t[rs].si) t[rt].t101+=t[ls].t101; t[rt].t100=max3(t[ls].t101+t[rs].t110,t[ls].t100,t[rs].t100); t[rt].t010=t[ls].t010; if (t[ls].t010==t[ls].si) t[rt].t010+=t[rs].t010; t[rt].t001=t[rs].t001; if (t[rs].t001==t[rs].si) t[rt].t001+=t[ls].t001; t[rt].t000=max3(t[ls].t001+t[rs].t010,t[ls].t000,t[rs].t000); } void build(int rt,int le,int ri){ t[rt].add=-1,t[rt].le=le,t[rt].ri=ri,t[rt].si=ri-le+1; if (le==ri){ t[rt].tot=t[rt].t101=t[rt].t110=ra[le]; t[rt].t001=t[rt].t010=!ra[le]; return; } int mid=(le+ri)/2,ls=rt*2,rs=rt*2+1; build(ls,le,mid); build(rs,mid+1,ri); pushup(rt); } void pushnew(int rt,int op){ if (op<2) t[rt].add=op; else if (t[rt].add==-1) t[rt].add=2; else if (t[rt].add==2) t[rt].add=-1; else t[rt].add=!t[rt].add; if (op==0) t[rt].tot=t[rt].t100=t[rt].t101=t[rt].t110=0,t[rt].t000=t[rt].t010=t[rt].t001=t[rt].si; else if (op==1) t[rt].tot=t[rt].t100=t[rt].t101=t[rt].t110=t[rt].si,t[rt].t000=t[rt].t010=t[rt].t001=0; else if (op==2){ t[rt].tot=t[rt].si-t[rt].tot; swap(t[rt].t000,t[rt].t100); swap(t[rt].t010,t[rt].t110); swap(t[rt].t001,t[rt].t101); } } void pushdown(int rt){ if (t[rt].add!=-1){ pushnew(rt*2,t[rt].add); pushnew(rt*2+1,t[rt].add); t[rt].add=-1; } } void update(int rt,int le,int ri,int xle,int xri,int op){ if (le>xri||ri<xle) return; if (xle<=le&&ri<=xri){ pushnew(rt,op); return; } pushdown(rt); int mid=(le+ri)/2; update(rt*2,le,mid,xle,xri,op); update(rt*2+1,mid+1,ri,xle,xri,op); pushup(rt); } int querytot(int rt,int le,int ri,int xle,int xri){ if (le>xri||ri<xle) return 0; if (xle<=le&&ri<=xri) return t[rt].tot; pushdown(rt); int mid=(le+ri)/2; return querytot(rt*2,le,mid,xle,xri)+querytot(rt*2+1,mid+1,ri,xle,xri); } Segtree query(int rt,int le,int ri,int xle,int xri){ Segtree ans; ans.set(le,ri); if (le>xri||ri<xle) return ans; if (xle<=le&&ri<=xri) return t[rt]; pushdown(rt); int mid=(le+ri)/2; Segtree ls=query(rt*2,le,mid,xle,xri),rs=query(rt*2+1,mid+1,ri,xle,xri); ans.t110=ls.t110; if (ls.t110==ls.si) ans.t110+=rs.t110; ans.t101=rs.t101; if (rs.t101==rs.si) ans.t101+=ls.t101; ans.t100=max3(ls.t101+rs.t110,ls.t100,rs.t100); ans.t010=ls.t010; if (ls.t010==ls.si) ans.t010+=rs.t010; ans.t001=rs.t001; if (rs.t001==rs.si) ans.t001+=ls.t001; ans.t000=max3(ls.t001+rs.t010,ls.t000,rs.t000); return ans; } int queryans(int a,int b){ Segtree tt=query(1,1,n,a,b); return max3(tt.t100,tt.t101,tt.t110); } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&ra[i]); build(1,1,n); for (int i=1;i<=m;i++){ scanf("%d%d%d",&op,&a,&b); a++,b++; if (op<3) update(1,1,n,a,b,op); else if (op==3) printf("%d\n",querytot(1,1,n,a,b)); else if (op==4){ printf("%d\n",queryans(a,b)); } } return 0; }