【SCOI2010】序列操作 线段树
2017-03-24 14:14
274 查看
题目描述
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<=n, m<=100000样例输入
10 100 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
样例输出
52
6
5
解题思路
维护一些属性与标记(什么属性什么标记就略了A.A)注意rev应该是rev[x]^=1,而不是rev[x]=1
还有如果将一段区间改为了0或1,应该删掉rev标记
害我调了一中午QWQ
代码
#include <bits/stdc++.h> using namespace std; inline int Getint(){int x=0,f=1;char ch=getchar();while('0'>ch||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} struct node{ int L,r,Sum[2],MaxL[2],Maxr[2],Max[2],c1,c0,rev; }Tree[400005]; int vl[100005]; int GetSize(int v){ return Tree[v].r-Tree[v].L+1; } void PushUp(int v,int op){ Tree[v].Sum[op]=Tree[2*v].Sum[op]+Tree[2*v+1].Sum[op]; Tree[v].MaxL[op]=Tree[2*v].MaxL[op]+(Tree[2*v].MaxL[op]==GetSize(2*v)?Tree[2*v+1].MaxL[op]:0); Tree[v].Maxr[op]=Tree[2*v+1].Maxr[op]+(Tree[2*v+1].Maxr[op]==GetSize(2*v+1)?Tree[2*v].Maxr[op]:0); Tree[v].Max[op]=max(Tree[2*v].Max[op],Tree[2*v+1].Max[op]); Tree[v].Max[op]=max(Tree[v].MaxL[op],Tree[v].Max[op]); Tree[v].Max[op]=max(Tree[v].Maxr[op],Tree[v].Max[op]); Tree[v].Max[op]=max(Tree[2*v].Maxr[op]+Tree[2*v+1].MaxL[op],Tree[v].Max[op]); } int PushUp(int v){PushUp(v,0);PushUp(v,1);return 0;} void PushDown(int v){ if(Tree[v].c1){ Tree[2*v].c0=0; Tree[2*v].c1=1; Tree[2*v].rev=0; Tree[2*v].Max[0]=Tree[2*v].Sum[0]=Tree[2*v].MaxL[0]=Tree[2*v].Maxr[0]=0; Tree[2*v].Max[1]=Tree[2*v].Sum[1]=Tree[2*v].MaxL[1]=Tree[2*v].Maxr[1]=GetSize(2*v); Tree[2*v+1].c0=0; Tree[2*v+1].c1=1; Tree[2*v+1].rev=0; Tree[2*v+1].Max[0]=Tree[2*v+1].Sum[0]=Tree[2*v+1].MaxL[0]=Tree[2*v+1].Maxr[0]=0; Tree[2*v+1].Max[1]=Tree[2*v+1].Sum[1]=Tree[2*v+1].MaxL[1]=Tree[2*v+1].Maxr[1]=GetSize(2*v+1); Tree[v].c1=0; } if(Tree[v].c0){ Tree[2*v].c1=0; Tree[2*v].c0=1; Tree[2*v].rev=0; Tree[2*v].Max[1]=Tree[2*v].Sum[1]=Tree[2*v].MaxL[1]=Tree[2*v].Maxr[1]=0; Tree[2*v].Max[0]=Tree[2*v].Sum[0]=Tree[2*v].MaxL[0]=Tree[2*v].Maxr[0]=GetSize(2*v); Tree[2*v+1].c1=0; Tree[2*v+1].c0=1; Tree[2*v+1].rev=0; Tree[2*v+1].Max[1]=Tree[2*v+1].Sum[1]=Tree[2*v+1].MaxL[1]=Tree[2*v+1].Maxr[1]=0; Tree[2*v+1].Max[0]=Tree[2*v+1].Sum[0]=Tree[2*v+1].MaxL[0]=Tree[2*v+1].Maxr[0]=GetSize(2*v+1); Tree[v].c0=0; } if(Tree[v].rev){ Tree[2*v].rev^=1; Tree[2*v+1].rev^=1; swap(Tree[2*v].Max[0],Tree[2*v].Max[1]); swap(Tree[2*v].Sum[0],Tree[2*v].Sum[1]); swap(Tree[2*v].MaxL[0],Tree[2*v].MaxL[1]); swap(Tree[2*v].Maxr[0],Tree[2*v].Maxr[1]); swap(Tree[2*v+1].Sum[0],Tree[2*v+1].Sum[1]); swap(Tree[2*v+1].Max[0],Tree[2*v+1].Max[1]); swap(Tree[2*v+1].MaxL[0],Tree[2*v+1].MaxL[1]); swap(Tree[2*v+1].Maxr[0],Tree[2*v+1].Maxr[1]); Tree[v].rev=0; } } void Build(int v,int L,int r){ Tree[v]=(node){L,r,0,0,0,0,0,0,0,0,0,0,0}; if(L==r)return; Build(2*v,L,(L+r)/2); Build(2*v+1,(L+r)/2+1,r); } void Make_Same(int v,int L,int r,int op){ if(r<Tree[v].L||Tree[v].r<L)return; if(L<=Tree[v].L&&Tree[v].r<=r){ if(op==0)Tree[v].c0=1,Tree[v].c1=0,Tree[v].rev=0; if(op==1)Tree[v].c0=0,Tree[v].c1=1,Tree[v].rev=0; Tree[v].Max[!op]=Tree[v].Sum[!op]=Tree[v].MaxL[!op]=Tree[v].Maxr[!op]=0; Tree[v].Max[op]=Tree[v].Sum[op]=Tree[v].MaxL[op]=Tree[v].Maxr[op]=GetSize(v); return; } PushDown(v); Make_Same(2*v,L,r,op); Make_Same(2*v+1,L,r,op); PushUp(v); } void Rev(int v,int L,int r){ if(r<Tree[v].L||Tree[v].r<L)return; if(L<=Tree[v].L&&Tree[v].r<=r){ Tree[v].rev^=1; swap(Tree[v].Max[0],Tree[v].Max[1]); swap(Tree[v].Sum[0],Tree[v].Sum[1]); swap(Tree[v].MaxL[0],Tree[v].MaxL[1]); swap(Tree[v].Maxr[0],Tree[v].Maxr[1]); return; } PushDown(v); Rev(2*v,L,r); Rev(2*v+1,L,r); PushUp(v); } int AskTot(int v,int L,int r){ if(r<Tree[v].L||Tree[v].r<L)return 0; if(L<=Tree[v].L&&Tree[v].r<=r) return Tree[v].Sum[1]; PushDown(v); return AskTot(2*v,L,r)+AskTot(2*v+1,L,r); } int Ask(int v,int L,int r){ if(r<Tree[v].L||Tree[v].r<L)return 0; if(L<=Tree[v].L&&Tree[v].r<=r) return Tree[v].Max[1]; PushDown(v); int t=max(Ask(2*v,L,r),Ask(2*v+1,L,r)); t=max(t,min(Tree[2*v+1].L+Tree[2*v+1].MaxL[1]-1,r)-max(Tree[2*v].r-Tree[2*v].Maxr[1]+1,L)+1); return t; } int main(){ int n=Getint(),m=Getint(); for(int i=1;i<=n;i++)vl[i]=Getint(); Build(1,1,n); for(int i=1;i<=n;i++)Make_Same(1,i,i,vl[i]); while(m--){ int op=Getint(),L=Getint()+1,r=Getint()+1; if(op==0||op==1)Make_Same(1,L,r,op); if(op==2)Rev(1,L,r); if(op==3)cout<<AskTot(1,L,r)<<"\n"; if(op==4)cout<<Ask(1,L,r)<<"\n"; } return 0; }
相关文章推荐
- 【SCOI2010】【线段树】序列操作
- BZOJ 1858 [Scoi2010]序列操作 - 线段树
- [省选] [线段树] [BZOJ1858] [SCOI2010] 序列操作
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
- BZOJ 1858: [Scoi2010]序列操作 线段树
- BZOJ 1858: [Scoi2010]序列操作 线段树区间修改查询
- 1858: [Scoi2010]序列操作 线段树
- 【BZOJ1858】[Scoi2010]序列操作【线段树】
- HYSBZ 1858(Scoi2010) 序列操作(线段树+区间合并)
- bzoj 1858: [Scoi2010]序列操作(线段树)
- BZOJ 1858: [Scoi2010]序列操作 [线段树]
- [SCOI2010]序列操作[分块or线段树]
- BZOJ 1858 SCOI2010 序列操作 线段树
- BZOJ 1858: [Scoi2010]序列操作 线段树
- bzoj 1858: [Scoi2010]序列操作 线段树
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
- 【BZOJ 1858】【SCOI 2010】序列操作【区间线段树】
- 【BZOJ】【P1858】【Scoi2010】【序列操作】【题解】【线段树】
- BZOJ 1858 [Scoi2010]序列操作 线段树
- 线段树——BZOJ1858/Luogu2572 [SCOI2010]序列操作