您的位置:首页 > 其它

BZOJ1858[Scoi2010]序列操作 题解

2016-08-03 18:25 141 查看
题目大意:

  有一个01序列,现在对于这个序列有五种变换操作和询问操作: 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。

思路:

  维护每一段数的和、左端和右端以及整段中连续的0和1的长度,并使用标记进行下传。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define N 400000
using namespace std;

int root,num,cnt,lmax[2]
,rmax[2]
,mmax[2]
,sum
,tag[2]
,rev
,h
,t
,rc
,lc
,a
;

void up_date(int x,int k)
{
int l=lc[x],r=rc[x];
lmax[k][x]=lmax[k][l],rmax[k][x]=rmax[k][r];
if (lmax[k][l]==t[l]-h[l]+1) lmax[k][x]+=lmax[k][r];
if (rmax[k][r]==t[r]-h[r]+1) rmax[k][x]+=rmax[k][l];
mmax[k][x]=max(max(mmax[k][l],mmax[k][r]),rmax[k][l]+lmax[k][r]);
}

void build(int l,int r,int &cur)
{
cur=++num,tag[0][cur]=tag[1][cur]=rev[cur]=0;
h[cur]=l,t[cur]=r;
if (l==r)
{
lc[cur]=rc[cur]=0;
lmax[0][cur]=rmax[0][cur]=mmax[0][cur]=(a[l]==0);
lmax[1][cur]=rmax[1][cur]=sum[cur]=mmax[1][cur]=(a[r]==1);
return;
}
int mid=l+r>>1;
build(l,mid,lc[cur]),build(mid+1,r,rc[cur]);
up_date(cur,0),up_date(cur,1),sum[cur]=sum[lc[cur]]+sum[rc[cur]];
}

void mark(int x,int k)
{
tag[k][x]=1,tag[k^1][x]=rev[x]=0,sum[x]=(t[x]-h[x]+1)*k;
lmax[k][x]=rmax[k][x]=mmax[k][x]=t[x]-h[x]+1;
lmax[k^1][x]=rmax[k^1][x]=mmax[k^1][x]=0;
}

void re(int x)
{
rev[x]^=1,sum[x]=t[x]-h[x]+1-sum[x];
swap(lmax[0][x],lmax[1][x]),swap(rmax[0][x],rmax[1][x]),swap(mmax[0][x],mmax[1][x]);
}

void push_down(int x)
{
if (tag[0][x]) mark(lc[x],0),mark(rc[x],0),tag[0][x]=0;
if (tag[1][x]) mark(lc[x],1),mark(rc[x],1),tag[1][x]=0;
if (rev[x]) re(lc[x]),re(rc[x]),rev[x]=0;
}

void change(int l,int r,int cur,int k)
{
if (h[cur]>r || t[cur]<l) return;
if (h[cur]>=l && t[cur]<=r)
{
if (k<2) mark(cur,k);
else re(cur);
return;
}
push_down(cur);
change(l,r,lc[cur],k),change(l,r,rc[cur],k);
up_date(cur,0),up_date(cur,1),sum[cur]=sum[lc[cur]]+sum[rc[cur]];
}

int ask1(int l,int r,int cur)
{
if (h[cur]>r || t[cur]<l) return 0;
if (h[cur]>=l && t[cur]<=r) return sum[cur];
push_down(cur);
return ask1(l,r,lc[cur])+ask1(l,r,rc[cur]);
}

int ask2(int l,int r,int cur)
{
if (l==h[cur] && r==t[cur]) return cur;
int mid=h[cur]+t[cur]>>1;
push_down(cur);
if (r<=mid) return ask2(l,r,lc[cur]);
else if (l>mid) return ask2(l,r,rc[cur]);
else
{
int ans=++cnt;
lc[ans]=ask2(l,mid,lc[cur]),rc[ans]=ask2(mid+1,r,rc[cur]);
up_date(ans,0),up_date(ans,1),sum[ans]=sum[lc[ans]]+sum[rc[ans]];
return ans;
}
}

int main()
{
int n,m,i,x,y,z;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,root);
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&z,&x,&y);
x++,y++;
if (z==3) printf("%d\n",ask1(x,y,root));
else if (z==4) cnt=num,printf("%d\n",mmax[1][ask2(x,y,root)]);
else change(x,y,root,z);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: