BZOJ 1858 SCOI2010 序列操作 線段樹
阿新 • • 發佈:2019-01-29
題目大意:給定一個01序列,提供三種操作:
0:把一段區間的所有元素都變成0
1:把一段區間的所有元素都變成1
2:把一段區間內的所有元素全都取反
3:查詢一段區間內1的個數
4:查詢一段區間內最長的一段連續的1
首先如果沒有操作4這就是bitset的水題。。。多了這個,我們考慮線段樹
線段樹的每一個節點存修改標記和翻轉標記,以及該區間的資訊
雖然查詢的資訊都是1 但是我們要連0一起儲存 因為翻轉後0就變成了1 1就變成了0
區間資訊包括:
左端點的元素
右端點的元素
左端點開始的最長的連續元素長度
右端點開始的最長的連續元素長度
最長的連續的1的長度
最長的連續的0的長度
更新時仔細討論即可
注意當一個點被附加上修改標記的時候 要把翻轉標記清零 下傳時要先下傳修改標記
這題是我寫過的最長的線段樹。。。樹鏈剖分除外
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 100100 #define root 0,1,n #define ls tree[p].lson #define rs tree[p].rson using namespace std; struct seq{ int cnt; bool lflag,rflag; int lmax,rmax; int max[2]; seq(bool flag,int len) { cnt=flag?len:0; lflag=rflag=flag; lmax=rmax=len; max[!flag]=0; max[ flag]=len; } void flip(int x,int y) { lflag^=1; rflag^=1; swap(max[0],max[1]); cnt=(y-x+1)-cnt; } }; seq un(seq*s1,seq*s2,int x,int y) { seq re(0,0); int mid=x+y>>1; re.cnt=s1->cnt+s2->cnt; re.lflag=s1->lflag; re.rflag=s2->rflag; if( s1->lmax==(mid-x+1) && s1->lflag==s2->lflag ) re.lmax=(mid-x+1)+s2->lmax; else re.lmax=s1->lmax; if( s2->rmax==(y-mid) && s2->rflag==s1->rflag ) re.rmax=(y-mid)+s1->rmax; else re.rmax=s2->rmax; re.max[0]=max(s1->max[0],s2->max[0]); re.max[1]=max(s1->max[1],s2->max[1]); if(s1->rflag==s2->lflag) re.max[s1->rflag]=max(re.max[s2->lflag],s1->rmax+s2->lmax); return re; } struct abcd{ int lson,rson; int change_mark; bool flip_mark; seq *s; }tree[M<<1]; int n,m,tot; void Build_Tree(int p,int x,int y) { int mid=x+y>>1; tree[p].change_mark=-1; if(x==y) { scanf("%d",&mid); tree[p].s=new seq(mid,1); return ; } ls=++tot;rs=++tot; Build_Tree(ls,x,mid); Build_Tree(rs,mid+1,y); tree[p].s=new seq(0,0); *tree[p].s=un(tree[ls].s,tree[rs].s,x,y); } void push_down(int p,int x,int y) { int mid=x+y>>1; if(~tree[p].change_mark) { tree[ls].change_mark=tree[p].change_mark; tree[rs].change_mark=tree[p].change_mark; tree[ls].flip_mark=0; tree[rs].flip_mark=0; *tree[ls].s=seq(tree[p].change_mark,mid-x+1); *tree[rs].s=seq(tree[p].change_mark,y-mid); tree[p].change_mark=-1; } if(tree[p].flip_mark) { tree[p].flip_mark=0; tree[ls].flip_mark^=1; tree[rs].flip_mark^=1; tree[ls].s->flip(x,mid); tree[rs].s->flip(mid+1,y); } } void change(int p,int x,int y,int l,int r,int v) { int mid=x+y>>1; if(x==l&&y==r) { tree[p].change_mark=v; tree[p].flip_mark=0; *tree[p].s=seq(v,y-x+1); return ; } push_down(p,x,y); if(r<=mid) change(ls,x,mid,l,r,v); else if(l>mid) change(rs,mid+1,y,l,r,v); else change(ls,x,mid,l,mid,v),change(rs,mid+1,y,mid+1,r,v); *tree[p].s=un(tree[ls].s,tree[rs].s,x,y); } void flip(int p,int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) { tree[p].flip_mark^=1; tree[p].s->flip(x,y); return ; } push_down(p,x,y); if(r<=mid) flip(ls,x,mid,l,r); else if(l>mid) flip(rs,mid+1,y,l,r); else flip(ls,x,mid,l,mid),flip(rs,mid+1,y,mid+1,r); *tree[p].s=un(tree[ls].s,tree[rs].s,x,y); } int count(int p,int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return tree[p].s->cnt; push_down(p,x,y); if(r<=mid) return count(ls,x,mid,l,r); if(l>mid) return count(rs,mid+1,y,l,r); return count(ls,x,mid,l,mid)+count(rs,mid+1,y,mid+1,r); } seq sequence(int p,int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return *tree[p].s; push_down(p,x,y); if(r<=mid) return sequence(ls,x,mid,l,r); if(l>mid) return sequence(rs,mid+1,y,l,r); seq s1=sequence(ls,x,mid,l,mid); seq s2=sequence(rs,mid+1,y,mid+1,r); return un(&s1,&s2,x,y); } int main() { int i,p,x,y; cin>>n>>m; Build_Tree(root); for(i=1;i<=m;i++) { scanf("%d%d%d",&p,&x,&y); x++;y++; switch(p) { case 0: case 1:change(root,x,y,p);break; case 2:flip(root,x,y);break; case 3:printf("%d\n", count(root,x,y) );break; case 4:printf("%d\n", sequence(root,x,y).max[1] );break; } } return 0; }