BZOJ1858: [Scoi2010]序列操作
Description
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都需要给出回答,聪明的程序员们,你们能帮助他吗?
Input
输入数据第一行包括2个数,n和m,分别表示序列的长度和操作数目
第二行包括n个数,表示序列的初始状态
接下来m行,每行3个数,op, a, b,(0 < = op < = 4,0 < = a < = b)
Output
对于每一个询问操作,输出一行,包括1个数,表示其对应的答案
Sample Input
10 10
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
0 0 0 1 1 0 1 0 1 1
1 0 2
3 0 5
2 2 2
4 0 4
0 3 6
2 3 7
4 2 8
1 0 5
0 5 6
3 3 9
Sample Output
5
2
6
5
2
6
5
HINT
对于30%的数据,1<=n, m<=1000
对于100%的数据,1< = n, m < = 100000
题解Here!
看到 区间修改+区间查询。。。
去吧,线段树。。。
于是一个晚上就没了。。。
恶心啊!!!
线段树记录:
区间和值;
区间最长0、1的长度;
从左端点开始最长0、1的长度,从右端点开始最长0、1的长度;
两个标记:全赋0/1,取反;
左右端点。
3很好做,4呢?
我们有一个O(nlogn)的分治算法,但是因为有O(n)的算法,前者就被我们抛弃了。。。
这时候,它的强大就体现了出来!
所以求4时,返回的不是一个值,而是一个线段树节点。
修改时,若正在改某区间的 全赋0/1 标记,记得将 取反 标记清0,巨坑。。。
还有上传,下传很重要,但是太恶心,不想多说,看代码吧。。。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define LSON rt<<1 #define RSON rt<<1|1 #define DATA(x) a[x].data #define SIGN1(x) a[x].c #define SIGN2(x) a[x].v #define SUM1(x) a[x].sum1 #define SUM2(x) a[x].sum2 #define LEFT1(x) a[x].left1 #define LEFT2(x) a[x].left2 #define RIGHT1(x) a[x].right1 #define RIGHT2(x) a[x].right2 #define LSIDE(x) a[x].l #define RSIDE(x) a[x].r #define WIDTH(x) (RSIDE(x)-LSIDE(x)+1) #define MAXN 100010 using namespace std; int n,m; struct node{ int data,c,v,left1,right1,sum1,left2,right2,sum2; int l,r; }a[MAXN<<2]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } void pushup(int rt){ DATA(rt)=DATA(LSON)+DATA(RSON); SUM1(rt)=max(RIGHT1(LSON)+LEFT1(RSON),max(SUM1(LSON),SUM1(RSON))); SUM2(rt)=max(RIGHT2(LSON)+LEFT2(RSON),max(SUM2(LSON),SUM2(RSON))); LEFT1(rt)=LEFT1(LSON);RIGHT1(rt)=RIGHT1(RSON); LEFT2(rt)=LEFT2(LSON);RIGHT2(rt)=RIGHT2(RSON); if(LEFT1(LSON)==WIDTH(LSON))LEFT1(rt)+=LEFT1(RSON); if(LEFT2(LSON)==WIDTH(LSON))LEFT2(rt)+=LEFT2(RSON); if(RIGHT1(RSON)==WIDTH(RSON))RIGHT1(rt)+=RIGHT1(LSON); if(RIGHT2(RSON)==WIDTH(RSON))RIGHT2(rt)+=RIGHT2(LSON); } void pushdown(int rt){ if(LSIDE(rt)==RSIDE(rt))return; if(SIGN1(rt)!=-1){ SIGN1(LSON)=SIGN1(rt); SIGN2(LSON)=0; DATA(LSON)=SUM2(LSON)=LEFT2(LSON)=RIGHT2(LSON)=SIGN1(rt)*WIDTH(LSON); SUM1(LSON)=LEFT1(LSON)=RIGHT1(LSON)=(SIGN1(rt)^1)*WIDTH(LSON); SIGN1(RSON)=SIGN1(rt); SIGN2(RSON)=0; DATA(RSON)=SUM2(RSON)=LEFT2(RSON)=RIGHT2(RSON)=SIGN1(rt)*WIDTH(RSON); SUM1(RSON)=LEFT1(RSON)=RIGHT1(RSON)=(SIGN1(rt)^1)*WIDTH(RSON); SIGN1(rt)=-1; } if(SIGN2(rt)){ SIGN2(LSON)^=1; DATA(LSON)=WIDTH(LSON)-DATA(LSON); swap(SUM1(LSON),SUM2(LSON)); swap(LEFT1(LSON),LEFT2(LSON));swap(RIGHT1(LSON),RIGHT2(LSON)); SIGN2(RSON)^=1; DATA(RSON)=WIDTH(RSON)-DATA(RSON); swap(SUM1(RSON),SUM2(RSON)); swap(LEFT1(RSON),LEFT2(RSON));swap(RIGHT1(RSON),RIGHT2(RSON)); SIGN2(rt)=0; } } void buildtree(int l,int r,int rt){ int mid; LSIDE(rt)=l;RSIDE(rt)=r; SIGN1(rt)=-1;SIGN2(rt)=0; if(l==r){ int x=read(); DATA(rt)=LEFT2(rt)=RIGHT2(rt)=SUM2(rt)=x; LEFT1(rt)=RIGHT1(rt)=SUM1(rt)=x^1; return; } mid=l+r>>1; buildtree(l,mid,LSON); buildtree(mid+1,r,RSON); pushup(rt); } void update_all(int l,int r,int c,int rt){ int mid; if(l<=LSIDE(rt)&&RSIDE(rt)<=r){ SIGN1(rt)=c; SIGN2(rt)=0; DATA(rt)=LEFT2(rt)=RIGHT2(rt)=SUM2(rt)=c*WIDTH(rt); LEFT1(rt)=RIGHT1(rt)=SUM1(rt)=(c^1)*WIDTH(rt); pushdown(rt); return; } pushdown(rt); mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)update_all(l,r,c,LSON); if(mid<r)update_all(l,r,c,RSON); pushup(rt); } void update_false(int l,int r,int rt){ int mid; if(l<=LSIDE(rt)&&RSIDE(rt)<=r){ SIGN2(rt)^=1; DATA(rt)=WIDTH(rt)-DATA(rt); swap(SUM1(rt),SUM2(rt)); swap(LEFT1(rt),LEFT2(rt));swap(RIGHT1(rt),RIGHT2(rt)); pushdown(rt); return; } pushdown(rt); mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)update_false(l,r,LSON); if(mid<r)update_false(l,r,RSON); pushup(rt); } int query_all(int l,int r,int rt){ int mid,ans=0; if(l<=LSIDE(rt)&&RSIDE(rt)<=r) return DATA(rt); pushdown(rt); mid=LSIDE(rt)+RSIDE(rt)>>1; if(l<=mid)ans+=query_all(l,r,LSON); if(mid<r)ans+=query_all(l,r,RSON); return ans; } node query_length(int l,int r,int rt){ int mid; if(l<=LSIDE(rt)&&RSIDE(rt)<=r) return a[rt]; pushdown(rt); mid=LSIDE(rt)+RSIDE(rt)>>1; node ans,ls,rs; ans=ls=rs=(node){0,0,0,0,0,0,0,0,0,0,0}; if(l<=mid)ls=query_length(l,r,LSON); if(mid<r)rs=query_length(l,r,RSON); ans.sum1=max(ls.right1+rs.left1,max(ls.sum1,rs.sum1)); ans.sum2=max(ls.right2+rs.left2,max(ls.sum2,rs.sum2)); ans.left1=ls.left1;ans.right1=rs.right1; ans.left2=ls.left2;ans.right2=rs.right2; if(ls.left1==WIDTH(LSON))ans.left1+=rs.left1; if(ls.left2==WIDTH(LSON))ans.left2+=rs.left2; if(rs.right1==WIDTH(RSON))ans.right1+=ls.right1; if(rs.right2==WIDTH(RSON))ans.right2+=ls.right2; return ans; } int main(){ int f,x,y; n=read();m=read(); buildtree(1,n,1); while(m--){ f=read();x=read()+1;y=read()+1; switch(f){ case 0:{ update_all(x,y,0,1); break; } case 1:{ update_all(x,y,1,1); break; } case 2:{ update_false(x,y,1); break; } case 3:{ printf("%d\n",query_all(x,y,1)); break; } case 4:{ node s=query_length(x,y,1); printf("%d\n",s.sum2); break; } } } return 0; }