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; }
本文来自博客园,作者:Glowingfire,转载请注明原文链接:https://www.cnblogs.com/Glowingfire/p/18654037
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程