bzoj 1858: [Scoi2010]序列操作 || 洛谷 P2572

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1858: [Scoi2010]序列操作 || 洛谷 P2572相关的知识,希望对你有一定的参考价值。

记一下:线段树占空间是$2^{ceil(log2(n))+1}$

这个就是一个线段树区间操作题,各种标记的设置、转移都很明确,只要熟悉这类题应该说是没有什么难度的。

由于对某区间set之后该区间原先待进行的取反操作失效(被覆盖),因此规定tag同时存在时set的标记先进行操作,这样对区间加上set标记时要去掉原有的取反标记。

对于操作4,线段树上每个区间维护6个值,分别表示:该区间最多的连续0/1,从左侧数起/从右侧数起/其中任意位置。题目中不问连续0,为什么连续0也要维护呢?这是为了在进行取反操作时,O(1)完成标记的维护(直接交换对0、1维护的3个值就行了)。

对于操作3,线段树上每个区间维护该区间1的个数。此时不需要额外记录0的个数,0的个数可以由区间总数-1的个数得到。

规定:set的标记为-1时表示不需要set操作,为0/1时表示需要set为该标记的值。

注意一点:对于取反的tag,每次取反操作的时候都是将tag取反,而不是置为1,不然在同一个位置取反两次就不对了。

各个标记含义同普通线段树:当前节点已经操作,其所有(任意级的)子节点待操作。维护的时候转移都是递推,细的就不讲了,有点多,要细心比对。

然而...

感觉自己药丸啊...调了三个小时才调出来,各种各样诡异的错误...如果省选考这个肯定没法做了..

幸好这个样例够强。。有一些奇怪的错误通过样例就查出来了,过了样例就1A了,不然真的不知道要调到什么时候。。。

note:以下程序中打了注释的语句都是错过的。。。

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define mid ((l+r)>>1)
  5 #define lc (num<<1)
  6 #define rc (num<<1|1)
  7 using namespace std;
  8 struct Th
  9 {
 10     int a,b,c;
 11     bool d;//是否全部是1
 12     int len;
 13     Th(int aa=0,int bb=0,int cc=0,bool dd=1,int ll=0):a(aa),b(bb),c(cc),d(dd),len(ll){}
 14 };
 15 int num1[270000],maxnum[270000][2][3],settag[270000];
 16 bool revtag[270000];
 17 int n,m;
 18 //定义tag同时存在时settag先进行操作
 19 int a[100010];
 20 int L,R,x;
 21 //maxnum[][0/1][0/1/2]表示最多的连续0/1,接左侧/接右侧/中间
 22 void pd(int l,int r,int num)
 23 {
 24     if(settag[num]!=-1)
 25     {
 26         num1[lc]=settag[num]*(mid-l+1);
 27         maxnum[lc][0][0]=maxnum[lc][0][1]=maxnum[lc][0][2]=(1-settag[num])*(mid-l+1);
 28         maxnum[lc][1][0]=maxnum[lc][1][1]=maxnum[lc][1][2]=settag[num]*(mid-l+1);
 29         num1[rc]=settag[num]*(r-mid);
 30         maxnum[rc][0][0]=maxnum[rc][0][1]=maxnum[rc][0][2]=(1-settag[num])*(r-mid);
 31         maxnum[rc][1][0]=maxnum[rc][1][1]=maxnum[rc][1][2]=settag[num]*(r-mid);
 32         revtag[lc]=revtag[rc]=0;
 33         settag[lc]=settag[rc]=settag[num];
 34         settag[num]=-1;
 35     }
 36     if(revtag[num])
 37     {
 38         num1[lc]=mid-l+1-num1[lc];
 39         num1[rc]=r-mid-num1[rc];
 40         swap(maxnum[lc][0][0],maxnum[lc][1][0]);
 41         swap(maxnum[lc][0][1],maxnum[lc][1][1]);
 42         swap(maxnum[lc][0][2],maxnum[lc][1][2]);
 43         swap(maxnum[rc][0][0],maxnum[rc][1][0]);
 44         swap(maxnum[rc][0][1],maxnum[rc][1][1]);
 45         swap(maxnum[rc][0][2],maxnum[rc][1][2]);
 46         revtag[lc]^=1;revtag[rc]^=1;
 47         revtag[num]=0;
 48     }
 49 }
 50 void update(int l,int r,int num)
 51 {
 52     num1[num]=num1[lc]+num1[rc];
 53     maxnum[num][0][0]=maxnum[lc][0][0];
 54     if(num1[lc]==0)    maxnum[num][0][0]=(mid-l+1)+maxnum[rc][0][0];
 55     maxnum[num][0][1]=maxnum[rc][0][1];
 56     if(num1[rc]==0)    maxnum[num][0][1]=(r-mid)+maxnum[lc][0][1];
 57     maxnum[num][1][0]=maxnum[lc][1][0];
 58     if(num1[lc]==mid-l+1)    maxnum[num][1][0]=(mid-l+1)+maxnum[rc][1][0];
 59     maxnum[num][1][1]=maxnum[rc][1][1];
 60     if(num1[rc]==r-mid)    maxnum[num][1][1]=(r-mid)+maxnum[lc][1][1];
 61     maxnum[num][0][2]=max(max(maxnum[lc][0][2],maxnum[rc][0][2]),maxnum[lc][0][1]+maxnum[rc][0][0]);
 62     maxnum[num][1][2]=max(max(maxnum[lc][1][2],maxnum[rc][1][2]),maxnum[lc][1][1]+maxnum[rc][1][0]);
 63 }
 64 void build(int l,int r,int num)
 65 {
 66     if(l==r)
 67     {
 68         num1[num]=(a[l]==1);
 69         maxnum[num][0][0]=maxnum[num][0][1]=maxnum[num][0][2]=(a[l]==0);
 70         maxnum[num][1][0]=maxnum[num][1][1]=maxnum[num][1][2]=(a[l]==1);
 71         settag[num]=-1;
 72         return;
 73     }
 74     build(l,mid,lc);
 75     build(mid+1,r,rc);
 76     settag[num]=-1;update(l,r,num);
 77 }
 78 void setto(int l,int r,int num)
 79 {
 80     if(L<=l&&r<=R)
 81     {
 82         revtag[num]=0;settag[num]=x;
 83         num1[num]=x*(r-l+1);//mid-l+1
 84         maxnum[num][0][0]=maxnum[num][0][1]=maxnum[num][0][2]=(1-x)*(r-l+1);//mid-l+1
 85         maxnum[num][1][0]=maxnum[num][1][1]=maxnum[num][1][2]=x*(r-l+1);//mid-l+1
 86         return;
 87     }
 88     pd(l,r,num);
 89     if(L<=mid)    setto(l,mid,lc);
 90     if(mid<R)    setto(mid+1,r,rc);
 91     update(l,r,num);
 92 }
 93 void revx(int l,int r,int num)
 94 {
 95     if(L<=l&&r<=R)
 96     {
 97         revtag[num]^=1;
 98         num1[num]=r-l+1-num1[num];
 99         swap(maxnum[num][0][0],maxnum[num][1][0]);
100         swap(maxnum[num][0][1],maxnum[num][1][1]);
101         swap(maxnum[num][0][2],maxnum[num][1][2]);
102         return;
103     }
104     pd(l,r,num);
105     if(L<=mid)    revx(l,mid,lc);
106     if(mid<R)    revx(mid+1,r,rc);
107     update(l,r,num);
108 }
109 int query1(int l,int r,int num)
110 {
111     if(L<=l&&r<=R)    return num1[num];
112     pd(l,r,num);
113     int ans=0;
114     if(L<=mid)    ans+=query1(l,mid,lc);
115     if(mid<R)    ans+=query1(mid+1,r,rc);
116     return ans;
117 }
118 Th query2(int l,int r,int num)
119 {
120     //if(L<=l&&r<=R)    return Th(maxnum[num][1][0],maxnum[num][1][1],maxnum[num][1][2],num1[num]==r-l+1,1);
121     if(L<=l&&r<=R)    return Th(maxnum[num][1][0],maxnum[num][1][1],maxnum[num][1][2],num1[num]==r-l+1,r-l+1);//num1[num]==1
122     pd(l,r,num);
123     Th ans,t1,t2;
124     if(L<=mid)    t1=query2(l,mid,lc);
125     if(mid<R)    t2=query2(mid+1,r,rc);
126     ans.a=t1.a;
127     //if(t1.d||t1.len==0)    ans.a=t1.len+t2.a;
128     if(t1.d)    ans.a=t1.len+t2.a;
129     ans.b=t2.b;
130     //if(t2.d||t2.len==0)    ans.b=t2.len+t1.b;
131     if(t2.d)    ans.b=t2.len+t1.b;
132     ans.c=max(max(t1.c,t2.c),t1.b+t2.a);
133     ans.d=t1.d&&t2.d;
134     ans.len=t1.len+t2.len;
135     return ans;
136 }
137 int main()
138 {
139     int i,idx;Th ttt;
140     scanf("%d%d",&n,&m);
141     for(i=1;i<=n;i++)    scanf("%d",&a[i]);
142     build(1,n,1);
143     for(i=1;i<=m;i++)
144     {
145         scanf("%d%d%d",&idx,&L,&R);L++,R++;
146         if(idx==0)    x=0,setto(1,n,1);
147         else if(idx==1)    x=1,setto(1,n,1);
148         else if(idx==2)    revx(1,n,1);
149         else if(idx==3)    printf("%d\n",query1(1,n,1));
150         else if(idx==4)    {ttt=query2(1,n,1);printf("%d\n",max(max(ttt.a,ttt.b),ttt.c));}
151     }
152     return 0;
153 }

以上是关于bzoj 1858: [Scoi2010]序列操作 || 洛谷 P2572的主要内容,如果未能解决你的问题,请参考以下文章

bzoj千题计划177:bzoj1858: [Scoi2010]序列操作

BZOJ_1858_[Scoi2010]序列操作_线段树

bzoj1858[Scoi2010]序列操作

AC日记——[Scoi2010]序列操作 bzoj 1858

bzoj 1858: [Scoi2010]序列操作

BZOJ 1858 SCOI2010 序列操作 线段树