hdu 3397 Sequence operation(线段树的延迟标记)
2013-01-18 13:01
711 查看
做这道题之前建议先做:hdu 3911是这道题的一部分,这是我的博客链接:/article/6394105.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的个数。
代码实现:
题意:首先给出一组数据:由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 .lone=p[n*2].lone; if(p[n*2].lone==p[n*2].mlen) p .lone+=p[n*2+1].lone; p .lzero=p[n*2].lzero; if(p[n*2].lzero==p[n*2].mlen)//左右子树可以合并 p .lzero+=p[n*2+1].lzero; p .rone=p[n*2+1].rone; if(p[n*2+1].rone==p[n*2+1].mlen)//左右子树可以合并 p .rone+=p[n*2].rone; p .rzero=p[n*2+1].rzero; if(p[n*2+1].rzero==p[n*2+1].mlen)//左右子树可以合并 p .rzero+=p[n*2].rzero; p .max1=max(p[n*2].max1,p[n*2+1].max1); p .max1=max(p .max1,p[n*2].rone+p[n*2+1].lone); p .max0=max(p[n*2].max0,p[n*2+1].max0); p .max0=max(p .max0,p[n*2].rzero+p[n*2+1].lzero); p .total1=p[n*2].total1+p[n*2+1].total1; } void build(int l,int r,int n)//建立线段树 { p .l=l; p .r=r; p .flag0=p .flag1=p .flag2=0; p .mlen=(r-l+1); if(l==r) { if(a[l]==1) { p .total1=1; p .lone=1; p .lzero=0; p .rone=1; p .rzero=0; p .max1=1; p .max0=0; } else { p .total1=0; p .lone=0; p .lzero=1; p .rone=0; p .rzero=1; p .max1=0; p .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 .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 .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 .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 .l&&p .r==y) { if(nima==0) { p .flag0=1; p .flag1=0; p .flag2=0; p .lone=0; p .lzero=p .mlen; p .rone=0; p .rzero=p .mlen; p .max1=0; p .max0=p .mlen; p .total1=0; return ; } else if(nima==1) { p .flag1=1; p .flag0=0; p .flag2=0; p .lone=p .mlen; p .lzero=0; p .rone=p .mlen; p .rzero=0; p .max1=p .mlen; p .max0=0; p .total1=p .mlen; return ; } else//如果是异或的话,先判断下flag0和flag1是0还是1 { p .flag2=p .flag2^1; if(p .flag0==1)//是1的话先往下更新 pushdown(n,0); if(p .flag1==1)//是1的话先往下更新 pushdown(n,1); swap(p .lone,p .lzero); swap(p .rone,p .rzero); swap(p .max1,p .max0); p .total1=p .mlen-p .total1; return ; } } if(p .l!=p .r) { if(p .flag0==1) pushdown(n,0); if(p .flag1==1) pushdown(n,1); if(p .flag2==1) pushdown(n,2); } int mid=(p .l+p .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 .mlen==p .max1) return y-x+1; if(p .mlen==p .max0) return 0; if(x==p .l&&y==p .r) return p .total1; if(p .l!=p .r) { if(p .flag0==1) pushdown(n,0); if(p .flag1==1) pushdown(n,1); if(p .flag2==1) pushdown(n,2); } int mid=(p .l+p .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 .mlen==p .max1) return y-x+1; if(p .mlen==p .max0) return 0; if(x==p .l&&y==p .r) return p .max1; if(p .l!=p .r) { if(p .flag0==1) pushdown(n,0); if(p .flag1==1) pushdown(n,1); if(p .flag2==1) pushdown(n,2); } int mid=(p .l+p .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; }
相关文章推荐
- HDU 3397 线段树 双懒惰标记
- E - Just a Hook HDU 1698 (线段树+类似延迟标记)
- HDU 1698 JUST a hook (线段树 成段替换 区间求和 延迟标记)
- hdu 1698 Just a Hook(线段树成段更新+延迟标记).
- 线段树,区间更改,延迟标记 hdu 1698
- hdu 3275线段树加延迟标记
- 线段树(类似延迟标记) HDU - 4027
- hdu1698-Just a Hook-线段树-整段区间的替换(延迟标记)
- HDU 1698 Just a Hook (线段树延迟标记(lazy))
- hdu 3275(线段树的延迟标记,我被坑了)
- hdu 3911 Black And White(线段树的延迟标记法)
- hdoj 3397 Sequence operation 【线段树区间覆盖 + 异或 + 合并】【维护延迟标记的顺序】
- 【hdu】 Just a Hook (线段树 -成段更新,延迟标记)
- HDU 3397 Sequence operation(线段树区间合并)
- HDU 4107(线段树 特殊懒惰标记)g++ TLE,c++才过(呜呜呜呜)
- HDU 3397 Sequence operation(线段树)
- HDU-3397 线段树+区间合并
- hdu 1698 Just a Hook(线段树,成段更新,懒惰标记)
- HDU 1698 Just a Hook(线段树延迟更新)
- hdu 4027 Can you answer these queries? 线段树 懒惰标记 单点更新妙用