做这道题之前建议先做:hdu 3911是这道题的一部分,这是我的博客链接:http://www.cnblogs.com/jiangjing/archive/2013/01/16/2863266.html
题意:首先给出一组数据:由0和1组成,然后有5种操作,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的个数。
代码实现:
#include<iostream> using namespace std; struct node{ int l,r; int lone,lzero;//分别是从左数1的个数和0的个数 int rone,rzero;//分别是从右数1的个数和0的个数 int max1,max0;//分别是连续的最多的1的个数和连续的最长0的个数 int total1,flag0,flag1,flag2,mlen;//分别是总共1的个数、是否进行了0操作,1操作,2操作的标记 }p[1000001];//这里有点坑开了100001*4的大小一直是Runtime erroy int a[1000001]; int max(int x,int y) { return x>y?x:y; } int min(int x,int y) { return x<y?x:y; } void pushup(int n)//往上更新 { p[n].lone=p[n*2].lone; if(p[n*2].lone==p[n*2].mlen) p[n].lone+=p[n*2+1].lone; p[n].lzero=p[n*2].lzero; if(p[n*2].lzero==p[n*2].mlen)//左右子树可以合并 p[n].lzero+=p[n*2+1].lzero; p[n].rone=p[n*2+1].rone; if(p[n*2+1].rone==p[n*2+1].mlen)//左右子树可以合并 p[n].rone+=p[n*2].rone; p[n].rzero=p[n*2+1].rzero; if(p[n*2+1].rzero==p[n*2+1].mlen)//左右子树可以合并 p[n].rzero+=p[n*2].rzero; p[n].max1=max(p[n*2].max1,p[n*2+1].max1); p[n].max1=max(p[n].max1,p[n*2].rone+p[n*2+1].lone); p[n].max0=max(p[n*2].max0,p[n*2+1].max0); p[n].max0=max(p[n].max0,p[n*2].rzero+p[n*2+1].lzero); p[n].total1=p[n*2].total1+p[n*2+1].total1; } void build(int l,int r,int n)//建立线段树 { p[n].l=l; p[n].r=r; p[n].flag0=p[n].flag1=p[n].flag2=0; p[n].mlen=(r-l+1); if(l==r) { if(a[l]==1) { p[n].total1=1; p[n].lone=1; p[n].lzero=0; p[n].rone=1; p[n].rzero=0; p[n].max1=1; p[n].max0=0; } else { p[n].total1=0; p[n].lone=0; p[n].lzero=1; p[n].rone=0; p[n].rzero=1; p[n].max1=0; p[n].max0=1; } return ; } int mid=(l+r)/2; build(l,mid,n*2); build(mid+1,r,n*2+1); pushup(n);//往上更新 } void pushdown(int n,int flag)//往下更新 { if(flag==0) { p[n*2].flag0=p[n*2+1].flag0=1; p[n*2].flag1=p[n*2].flag2=0;//flag1和flag2不管以前是0还是1全部变成0 p[n*2+1].flag1=p[n*2+1].flag2=0; p[n].flag0=0; p[n*2].total1=0; p[n*2].lone=0; p[n*2].lzero=p[n*2].mlen; p[n*2].rone=0; p[n*2].rzero=p[n*2].mlen; p[n*2].max1=0; p[n*2].max0=p[n*2].mlen; p[n*2+1].total1=0; p[n*2+1].lone=0; p[n*2+1].lzero=p[n*2+1].mlen; p[n*2+1].rone=0; p[n*2+1].rzero=p[n*2+1].mlen; p[n*2+1].max1=0; p[n*2+1].max0=p[n*2+1].mlen; } else if(flag==1) { p[n*2].flag1=p[n*2+1].flag1=1; p[n*2].flag0=p[n*2].flag2=0;//flag0和flag2不管以前是0还是1全部变成0 p[n*2+1].flag0=p[n*2+1].flag2=0; p[n].flag1=0; p[n*2].total1=p[n*2].mlen; p[n*2].lone=p[n*2].mlen; p[n*2].lzero=0; p[n*2].rone=p[n*2].mlen; p[n*2].rzero=0; p[n*2].max1=p[n*2].mlen; p[n*2].max0=0; p[n*2+1].total1=p[n*2+1].mlen; p[n*2+1].lone=p[n*2+1].mlen; p[n*2+1].lzero=0; p[n*2+1].rone=p[n*2+1].mlen; p[n*2+1].rzero=0; p[n*2+1].max1=p[n*2+1].mlen; p[n*2+1].max0=0; } else { p[n*2].flag2^=1; p[n*2+1].flag2^=1; p[n].flag2=0; swap(p[n*2].lone,p[n*2].lzero); swap(p[n*2].rone,p[n*2].rzero); swap(p[n*2].max1,p[n*2].max0); p[n*2].total1=p[n*2].mlen-p[n*2].total1; swap(p[n*2+1].lone,p[n*2+1].lzero); swap(p[n*2+1].rone,p[n*2+1].rzero); swap(p[n*2+1].max1,p[n*2+1].max0); p[n*2+1].total1=p[n*2+1].mlen-p[n*2+1].total1; } } void insert(int x,int y,int n,int nima)//更新 { if(x==p[n].l&&p[n].r==y) { if(nima==0) { p[n].flag0=1; p[n].flag1=0; p[n].flag2=0; p[n].lone=0; p[n].lzero=p[n].mlen; p[n].rone=0; p[n].rzero=p[n].mlen; p[n].max1=0; p[n].max0=p[n].mlen; p[n].total1=0; return ; } else if(nima==1) { p[n].flag1=1; p[n].flag0=0; p[n].flag2=0; p[n].lone=p[n].mlen; p[n].lzero=0; p[n].rone=p[n].mlen; p[n].rzero=0; p[n].max1=p[n].mlen; p[n].max0=0; p[n].total1=p[n].mlen; return ; } else//如果是异或的话,先判断下flag0和flag1是0还是1 { p[n].flag2=p[n].flag2^1; if(p[n].flag0==1)//是1的话先往下更新 pushdown(n,0); if(p[n].flag1==1)//是1的话先往下更新 pushdown(n,1); swap(p[n].lone,p[n].lzero); swap(p[n].rone,p[n].rzero); swap(p[n].max1,p[n].max0); p[n].total1=p[n].mlen-p[n].total1; return ; } } if(p[n].l!=p[n].r) { if(p[n].flag0==1) pushdown(n,0); if(p[n].flag1==1) pushdown(n,1); if(p[n].flag2==1) pushdown(n,2); } int mid=(p[n].l+p[n].r)/2; if(y<=mid) insert(x,y,n*2,nima); else if(x>mid) insert(x,y,n*2+1,nima); else { insert(x,mid,n*2,nima); insert(mid+1,y,n*2+1,nima); } pushup(n); } int sum1(int x,int y,int n)//求区间总共有多少个1 { if(p[n].mlen==p[n].max1) return y-x+1; if(p[n].mlen==p[n].max0) return 0; if(x==p[n].l&&y==p[n].r) return p[n].total1; if(p[n].l!=p[n].r) { if(p[n].flag0==1) pushdown(n,0); if(p[n].flag1==1) pushdown(n,1); if(p[n].flag2==1) pushdown(n,2); } int mid=(p[n].l+p[n].r)/2; if(y<=mid) sum1(x,y,n*2); else if(x>mid) sum1(x,y,n*2+1); else return sum1(x,mid,n*2)+sum1(mid+1,y,n*2+1); } int sum2(int x,int y,int n)//求区间连续1的最长的个数 { if(p[n].mlen==p[n].max1) return y-x+1; if(p[n].mlen==p[n].max0) return 0; if(x==p[n].l&&y==p[n].r) return p[n].max1; if(p[n].l!=p[n].r) { if(p[n].flag0==1) pushdown(n,0); if(p[n].flag1==1) pushdown(n,1); if(p[n].flag2==1) pushdown(n,2); } int mid=(p[n].l+p[n].r)/2; if(y<=mid) return sum2(x,y,n*2); else if(x>mid) return sum2(x,y,n*2+1); else { int left=0,right=0,midden=0; midden=midden+min(mid-x+1,p[n*2].rone)+min(y-mid,p[n*2+1].lone); left=sum2(x,mid,n*2); right=sum2(mid+1,y,n*2+1); return max(midden,max(left,right)); } } int main() { int T,n,m,i,nima,x,y; while(scanf("%d",&T)!=EOF) { while(T--) { scanf("%d%d",&n,&m); for(i=1;i<=n;i++) scanf("%d",&a[i]); build(1,n,1); while(m--) { scanf("%d%d%d",&nima,&x,&y); switch(nima) { case 0: insert(x+1,y+1,1,nima);break; case 1: insert(x+1,y+1,1,nima);break; case 2: insert(x+1,y+1,1,nima);break; case 3: printf("%d\n",sum1(x+1,y+1,1));break; case 4: printf("%d\n",sum2(x+1,y+1,1));break; } } } } return 0; }