bzoj 1858: [Scoi2010]序列操作
线段树
题意
给一个01串,设计数据结构,支持5种操作:
- 区间置零
- 区间置一
- 区间翻转,0变1,1变0
- 查询区间1的个数
- 查询区间内最长的连续1的个数
思路
线段树维护连续子区间。就是复杂一点而已。因为有翻转操作,所以要同时维护0和1的信息。
维护区间0、1的个数,区间最长连续0、1,最长前缀0、1,最长后缀0、1。
最好重载+号,pushup就相当于做加法。
代码
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define M(a,b) memset(a,b,sizeof(a))
using namespace std;
const int MAXN=100007;
const int oo=0x3f3f3f3f;
int max3(int a, int b, int c) { return std::max(std::max(a, b), c); }
int num[MAXN];
struct Stree
{
int flip;//翻转
int num0, num1;//0的个数,1的个数
int set0, set1;//置0,置1
int pre0, pre1;//连续前缀0,连续前缀1
int suf0, suf1;//连续后缀0,连续后缀1
int ma0, ma1;//最长连续0,最长连续1
inline void init() { flip=num0=num1=set0=set1=pre0=pre1=suf0=suf1=ma0=ma1=0; }
}stree[MAXN<<2];
void pushup(int l, int r, int rt)
{
stree[rt].num0=stree[rt<<1].num0+stree[rt<<1|1].num0;
stree[rt].num1=stree[rt<<1].num1+stree[rt<<1|1].num1;
stree[rt].ma0=max3(stree[rt<<1].ma0, stree[rt<<1|1].ma0, stree[rt<<1].suf0+stree[rt<<1|1].pre0);
stree[rt].ma1=max3(stree[rt<<1].ma1, stree[rt<<1|1].ma1, stree[rt<<1].suf1+stree[rt<<1|1].pre1);
int mid=(l+r)>>1;
if(stree[rt<<1].pre0==mid-l+1)
stree[rt].pre0=stree[rt<<1].pre0+stree[rt<<1|1].pre0;
else stree[rt].pre0=stree[rt<<1].pre0;
if(stree[rt<<1].pre1==mid-l+1)
stree[rt].pre1=stree[rt<<1].pre1+stree[rt<<1|1].pre1;
else stree[rt].pre1=stree[rt<<1].pre1;
if(stree[rt<<1|1].suf0==r-mid)
stree[rt].suf0=stree[rt<<1].suf0+stree[rt<<1|1].suf0;
else stree[rt].suf0=stree[rt<<1|1].suf0;
if(stree[rt<<1|1].suf1==r-mid)
stree[rt].suf1=stree[rt<<1].suf1+stree[rt<<1|1].suf1;
else stree[rt].suf1=stree[rt<<1|1].suf1;
}
void pushdown(int l, int r, int rt)
{
int mid=(l+r)>>1;
if(stree[rt].set0)
{
stree[rt].set0=0;
stree[rt<<1].flip=stree[rt<<1].set1=0;stree[rt<<1].set0=1;
stree[rt<<1].num0=mid-l+1;stree[rt<<1].num1=0;
stree[rt<<1].pre0=stree[rt<<1].suf0=stree[rt<<1].ma0=mid-l+1;
stree[rt<<1].pre1=stree[rt<<1].suf1=stree[rt<<1].ma1=0;
stree[rt<<1|1].flip=stree[rt<<1|1].set1=0;stree[rt<<1|1].set0=1;
stree[rt<<1|1].num0=r-mid;stree[rt<<1|1].num1=0;
stree[rt<<1|1].pre0=stree[rt<<1|1].suf0=stree[rt<<1|1].ma0=r-mid;
stree[rt<<1|1].pre1=stree[rt<<1|1].suf1=stree[rt<<1|1].ma1=0;
}
else if(stree[rt].set1)
{
stree[rt].set1=0;
stree[rt<<1].flip=stree[rt<<1].set0=0;stree[rt<<1].set1=1;
stree[rt<<1].num1=mid-l+1;stree[rt<<1].num0=0;
stree[rt<<1].pre1=stree[rt<<1].suf1=stree[rt<<1].ma1=mid-l+1;
stree[rt<<1].pre0=stree[rt<<1].suf0=stree[rt<<1].ma0=0;
stree[rt<<1|1].flip=stree[rt<<1|1].set0=0;stree[rt<<1|1].set1=1;
stree[rt<<1|1].num1=r-mid;stree[rt<<1|1].num0=0;
stree[rt<<1|1].pre1=stree[rt<<1|1].suf1=stree[rt<<1|1].ma1=r-mid;
stree[rt<<1|1].pre0=stree[rt<<1|1].suf0=stree[rt<<1|1].ma0=0;
}
else if(stree[rt].flip)
{
stree[rt].flip=0;
stree[rt<<1].flip^=1;
if(stree[rt<<1].set0) stree[rt<<1].set1=1, stree[rt<<1].set0=0, stree[rt<<1].flip=0;
else if(stree[rt<<1].set1) stree[rt<<1].set0=1, stree[rt<<1].set1=0, stree[rt<<1].flip=0;
swap(stree[rt<<1].ma0, stree[rt<<1].ma1);
swap(stree[rt<<1].num0, stree[rt<<1].num1);
swap(stree[rt<<1].pre0, stree[rt<<1].pre1);
swap(stree[rt<<1].suf0, stree[rt<<1].suf1);
stree[rt<<1|1].flip^=1;
if(stree[rt<<1|1].set0) stree[rt<<1|1].set1=1, stree[rt<<1|1].set0=0, stree[rt<<1|1].flip=0;
else if(stree[rt<<1|1].set1) stree[rt<<1|1].set0=1, stree[rt<<1|1].set1=0, stree[rt<<1|1].flip=0;
swap(stree[rt<<1|1].ma0, stree[rt<<1|1].ma1);
swap(stree[rt<<1|1].num0, stree[rt<<1|1].num1);
swap(stree[rt<<1|1].pre0, stree[rt<<1|1].pre1);
swap(stree[rt<<1|1].suf0, stree[rt<<1|1].suf1);
}
}
void build(int l, int r, int rt)
{
stree[rt].init();
if(l==r)
{
if(num[l]) stree[rt].num1=stree[rt].pre1=stree[rt].suf1=stree[rt].ma1=1;
else stree[rt].num0=stree[rt].pre0=stree[rt].suf0=stree[rt].ma0=1;
return;
}
int mid=(l+r)>>1;
build(lson), build(rson);
pushup(l, r, rt);
}
void update(int L, int R, int k, int l, int r, int rt)
{
if(L<=l&&r<=R)
{
if(k==0)//set0
{
if(stree[rt].set0) return;
else
{
stree[rt].set1=stree[rt].flip=0;stree[rt].set0=1;
stree[rt].num0=stree[rt].pre0=stree[rt].suf0=stree[rt].ma0=r-l+1;
stree[rt].num1=stree[rt].pre1=stree[rt].suf1=stree[rt].ma1=0;
}
}
else if(k==1)//set1
{
if(stree[rt].set1) return;
else
{
stree[rt].set0=stree[rt].flip=0;stree[rt].set1=1;
stree[rt].num0=stree[rt].pre0=stree[rt].suf0=stree[rt].ma0=0;
stree[rt].num1=stree[rt].pre1=stree[rt].suf1=stree[rt].ma1=r-l+1;
}
}
else if(k==2)//flip
{
if(stree[rt].set0) stree[rt].set0=0, stree[rt].set1=1, stree[rt].flip=0;
else if(stree[rt].set1) stree[rt].set0=1, stree[rt].set1=0, stree[rt].flip=0;
else stree[rt].flip^=1;
swap(stree[rt].ma0, stree[rt].ma1);
swap(stree[rt].num0, stree[rt].num1);
swap(stree[rt].pre0, stree[rt].pre1);
swap(stree[rt].suf0, stree[rt].suf1);
}
return;
}
pushdown(l, r, rt);
int mid=(l+r)>>1;
if(L<=mid) update(L, R, k, lson);
if(R>mid) update(L, R, k, rson);
pushup(l, r, rt);
}
int query1(int L, int R, int l, int r, int rt)
{
if(L<=l&&r<=R) return stree[rt].num1;
pushdown(l, r, rt);
int mid=(l+r)>>1;
int sum=0;
if(L<=mid) sum+=query1(L, R, lson);
if(mid<R) sum+=query1(L, R, rson);
return sum;
}
Stree query2(int L, int R, int l, int r, int rt)
{
if(L<=l&&r<=R) return stree[rt];
pushdown(l, r, rt);
int mid=(l+r)>>1;
Stree ll, rr;ll.init(), rr.init();
if(L<=mid) ll=query2(L, R, lson);
if(mid<R) rr=query2(L, R, rson);
Stree res;res.init();
res.ma1=max3(ll.ma1, rr.ma1, ll.suf1+rr.pre1);
if(ll.pre1==mid-l+1)
res.pre1=ll.pre1+rr.pre1;
else res.pre1=ll.pre1;
if(rr.suf1==r-mid)
res.suf1=ll.suf1+rr.suf1;
else res.suf1=rr.suf1;
return res;
}
int main()
{
int n, m;scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++) scanf("%d", &num[i]);
build(1, n, 1);
for(int i=1;i<=m;i++)
{
int op, x, y;scanf("%d%d%d", &op, &x, &y);x++, y++;
if(op==0)
update(x, y, 0, 1, n, 1);
else if(op==1)
update(x, y, 1, 1, n, 1);
else if(op==2)
update(x, y, 2, 1, n, 1);
else if(op==3)
printf("%d\n", query1(x, y, 1, n, 1));
else if(op==4)
printf("%d\n", query2(x, y, 1, n, 1).ma1);
}
//system("pause");
return 0;
}