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 }

原文地址:https://www.cnblogs.com/hehe54321/p/8525697.html

时间: 2024-10-14 11:28:57

bzoj 1858: [Scoi2010]序列操作 || 洛谷 P2572的相关文章

bzoj 1858: [Scoi2010] 序列操作 题解

[原题] 1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 1031  Solved: 529 [Submit][Status] Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内

bzoj 1858: [Scoi2010]序列操作

1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MB 线段树,对于每个区间需要分别维护左右中的1和0连续个数,并在op=4时特殊处理一下. Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区间内的所有数全

BZOJ 1858 SCOI2010 序列操作 线段树

题目大意:给定一个01序列,提供三种操作: 0:把一段区间的全部元素都变成0 1:把一段区间的全部元素都变成1 2:把一段区间内的全部元素全都取反 3:查询一段区间内1的个数 4:查询一段区间内最长的一段连续的1 首先假设没有操作4这就是bitset的水题... 多了这个,我们考虑线段树 线段树的每个节点存改动标记和翻转标记,以及该区间的信息 尽管查询的信息都是1 可是我们要连0一起保存 由于翻转后0就变成了1 1就变成了0 区间信息包含: 左端点的元素 右端点的元素 左端点開始的最长的连续元素

1858: [Scoi2010]序列操作

1858: [Scoi2010]序列操作 Description 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 对于每一

【BZOJ 1858】 [Scoi2010]序列操作

1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1368 Solved: 712 [Submit][Status][Discuss] Description lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b 把[a, b]区间内的所有数全变成1 2 a b 把[a,b]区

【题解】Luogu P2572 [SCOI2010]序列操作

原题传送门:P2572 [SCOI2010]序列操作 这题好弱智啊 裸的珂朵莉树 前置芝士:珂朵莉树 窝博客里对珂朵莉树的介绍 没什么好说的自己看看吧 操作1:把区间内所有数推平成0,珂朵莉树基本操作 操作2:把区间内所有数推平成1,珂朵莉树基本操作 操作3:把区间内所有数取反(异或1),split后扫描一遍,值域取反 操作4:区间和,珂朵莉树基本操作 操作5:区间最长连续的1,暴力扫描累加 就是这样简单 好像跑的比线段树还快???喵喵喵 #pragma GCC optimize("O3&quo

P2572 [SCOI2010]序列操作

对自己 & \(RNG\) : 骄兵必败 \(lpl\)加油! P2572 [SCOI2010]序列操作 题目描述 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 询

bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作

2333? 先记一下吧,这题现在全部都是照着题解做的,因为怎么改都改不出来,只好对着题解改,以后还要再做过 以后再也不用指针了!太恶心了!空指针可不止直接特判那么简单啊,竟然还要因为空指针写奇怪的分类讨论! 没错,就是那个诡异的55和63行.由于要返回删除x后x所在树的新根,要分类讨论:如果x是根且其两个子节点合并后为空,那么去掉x后新树树根为空:如果x是根且其两个子节点合并后不为空,那么去掉x后新树树根为两个子节点合并后的:如果x不是根,那么去掉x后新树树根为原来的find(x). 另外,打了

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

1858 思路: 恶心: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 struct TreeNodeType { int l,r,l1,r1,m1,l0,r0,m0,mid,size,cnt1,cnt0; bool f1,f0,ff; inline void turn(){swap(l1,l0),swap(r1,r0),swap(m1,m0),swap(cnt1,cnt0);} inline voi