P2572 [SCOI2010] 序列操作 —— 线段树

题意

原题

给定一个0/1序列,初始全为零要求分别实现:

-区间赋值

-区间取反

-询问区间1的个数

-询问区间为1的最大子段和

分析

形式化地定义变量,我们记下区间的0/1个数,0/1最大字段和,赋值与取反标记。

赋值的标记优先级大于取反标记,取反直接把区间赋值标记,区间0/1个数和最大子段和交换。

不复杂的题面,要注意很多细节,耐心写总能过。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100;
struct segtree
{
struct node
{
int val[2],l,r,siz;
int tag[2],xo;
int lsum[2],rsum[2],all[2];
node()
{
val[0]=val[1]=0;
l=r=siz=xo=0;
tag[0]=tag[1]=0;
lsum[0]=lsum[1]=rsum[0]=rsum[1]=0;
all[0]=all[1]=0;
}
}s[N<<2];
node ans;
void pushup(node &nw,node &lc,node &rc)
{
nw.siz=lc.siz+rc.siz;
for(int j=0;j<=1;++j)
{
nw.val[j]=lc.val[j]+rc.val[j];
nw.lsum[j]=lc.lsum[j];
nw.rsum[j]=rc.rsum[j];
if(lc.val[j]==lc.siz)
nw.lsum[j]=lc.siz+rc.lsum[j];
if(rc.val[j]==rc.siz)
nw.rsum[j]=rc.siz+lc.rsum[j];
nw.all[j]=lc.rsum[j]+rc.lsum[j];
nw.all[j]=max(max(lc.all[j],rc.all[j]),nw.all[j]);
nw.all[j]=max(max(nw.lsum[j],nw.rsum[j]) , nw.all[j]);
}
}
void build(int i,int l,int r,int g[])
{
s[i].l=l;
s[i].r=r;
s[i].siz=r-l+1;
if(l==r)
{
s[i].lsum[g[l]]=s[i].rsum[g[l]]=1;
s[i].all[g[l]]=s[i].val[g[l]]=1;
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid,g);
build(i<<1|1,mid+1,r,g);
pushup(s[i],s[i<<1],s[i<<1|1]);
}
void pushtag1(int i)
{
s[i].xo^=1;
swap(s[i].val[0],s[i].val[1]);
swap(s[i].lsum[0],s[i].lsum[1]);
swap(s[i].rsum[0],s[i].rsum[1]);
swap(s[i].all[0],s[i].all[1]);
swap(s[i].tag[0],s[i].tag[1]);
}
void pushtag2(int i,int z)
{
s[i].tag[z]=1;
s[i].tag[z^1]=0;
s[i].xo=0;
s[i].val[z]=s[i].siz;
s[i].val[z^1]=0;
//s[i].all[z]=1; !!!!!
s[i].all[z]=s[i].siz;
s[i].all[z^1]=0;
s[i].lsum[z]=s[i].rsum[z]=s[i].all[z]=s[i].siz;
s[i].lsum[z^1]=s[i].rsum[z^1]=s[i].all[z^1]=0;
}
void pushdown(int i)
{
if(!s[i].xo && !s[i].tag[0] && !s[i].tag[1])
return ;
if(s[i].tag[0]==1)
{
pushtag2(i<<1,0);
pushtag2(i<<1|1,0);
}
else if(s[i].tag[1]==1)
{
pushtag2(i<<1,1);
pushtag2(i<<1|1,1);
}
else if(s[i].xo==1)
{
pushtag1(i<<1);
pushtag1(i<<1|1);
}
s[i].xo=s[i].tag[0]=s[i].tag[1]=0;
}
void upd1(int i,int x,int y,int z)//turn to z
{
if(s[i].l>=x && s[i].r<=y)
{
pushtag2(i,z);
return ;
}
pushdown(i);
int mid=(s[i].l+s[i].r)>>1;
if(x<=mid)
upd1(i<<1,x,y,z);
if(y>mid)
upd1(i<<1|1,x,y,z);
pushup(s[i],s[i<<1],s[i<<1|1]);
}
void upd2(int i,int x,int y)//swap 0,1
{
if(s[i].l>=x && s[i].r<=y)
{
pushtag1(i);
return ;
}
pushdown(i);
int mid=(s[i].l+s[i].r)>>1;
if(x<=mid)
upd2(i<<1,x,y);
if(y>mid)
upd2(i<<1|1,x,y);
pushup(s[i],s[i<<1],s[i<<1|1]);
}
int que3(int i,int x,int y,int z)
{
if(s[i].l>=x && s[i].r<=y)
return s[i].val[z];
pushdown(i);
int mid=(s[i].l+s[i].r)>>1,sum=0;
if(x<=mid)
sum+=que3(i<<1,x,y,z);
if(y>mid)
sum+=que3(i<<1|1,x,y,z);
return sum;
}
void cl(node &nw)
{
nw.all[0]=nw.all[1]=0;
nw.lsum[0]=nw.lsum[1]=0;
nw.rsum[0]=nw.rsum[1]=0;
nw.val[0]=nw.val[1]=0;
nw.siz=0;
}
node que4(int i,int x,int y,int z)
{
if(s[i].l>=x && s[i].r<=y)
return s[i];
pushdown(i);
int mid=(s[i].l+s[i].r)>>1;
node emp,lc,rc;
if(x<=mid)
lc=que4(i<<1,x,y,z);
if(y>mid)
rc=que4(i<<1|1,x,y,z);
pushup(emp,lc,rc);
return emp;
}
int que5(int x,int y,int z)
{
ans=que4(1,x,y,z);
return ans.all[z];
}
}T;
int g[N],n,m;
void work()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",g+i);
T.build(1,1,n,g);
while(m--)
{
int opt,x,y;
scanf("%d%d%d",&opt,&x,&y);
++x;++y;
if(opt==0 || opt==1)
T.upd1(1,x,y,opt);
else if(opt==2)
T.upd2(1,x,y);
else
{
if(opt==3)
{
int ans=T.que3(1,x,y,1);
printf("%d\n",ans);
}
else
{
int ans=T.que5(x,y,1);
printf("%d\n",ans);
}
}
}
}
int main()
{
work();
return 0;
}
posted @   Glowingfire  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
点击右上角即可分享
微信分享提示