C36 线段树 P2572 [SCOI2010] 序列操作
视频链接:222 线段树 [SCOI2010] 序列操作_哔哩哔哩_bilibili
#include <iostream> #include <cstring> #include <algorithm> using namespace std; #define ls u<<1 #define rs u<<1|1 const int N=100005; int n,m,a[N]; struct tree{ int l,r; int b,lb,rb,mb,c,lc,rc,mc; int len,tag,rev; }tr[N<<2]; // b:区间1的个数, c:区间0的个数 //lb:区间左起1的长度, lc:区间左起0的长度 //rb:区间右起1的长度, rc:区间右起0的长度 //mb:区间1的最长长度, mc:区间0的最长长度 //len:区间的长度 //tag:区间赋值标记,无标记:-1,有标记:0或1 //rev:区间取反标记,无标记: 0,有标记:1 void pushup(tree& u,tree l,tree r){ //上传 u.b=l.b+r.b; u.lb=l.c ? l.lb : l.b+r.lb; u.rb=r.c ? r.rb : r.b+l.rb; u.mb=max(max(l.mb,r.mb),l.rb+r.lb); u.c=l.c+r.c; u.lc=l.b ? l.lc : l.c+r.lc; u.rc=r.b ? r.rc : r.c+l.rc; u.mc=max(max(l.mc,r.mc),l.rc+r.lc); } void pd(int u,int opt){ //操作区间 tree& t=tr[u]; if(opt==0){ //区间赋值为0 t.b=t.lb=t.rb=t.mb=0; t.c=t.lc=t.rc=t.mc=t.len; t.tag=0; t.rev=0; } if(opt==1){ //区间赋值为1 t.b=t.lb=t.rb=t.mb=t.len; t.c=t.lc=t.rc=t.mc=0; t.tag=1; t.rev=0; } if(opt==2){ //区间取反 swap(t.b,t.c);swap(t.lb,t.lc); swap(t.rb,t.rc);swap(t.mb,t.mc); t.rev^=1; } } void pushdown(int u){ //下传 tree& t=tr[u]; if(t.tag==0) pd(ls,0),pd(rs,0); if(t.tag==1) pd(ls,1),pd(rs,1); if(t.rev) pd(ls,2),pd(rs,2); t.tag=-1; t.rev=0; } void build(int u,int l,int r){ //建树 int t=a[l]; tr[u]={l,r,t,t,t,t, t^1,t^1,t^1,t^1,r-l+1,-1,0}; if(l==r) return; int m=l+r>>1; build(ls,l,m); build(rs,m+1,r); pushup(tr[u],tr[ls],tr[rs]); } void change(int u,int x,int y,int k){ //区修 if(y<tr[u].l || tr[u].r<x) return; if(x<=tr[u].l&&tr[u].r<=y){pd(u,k);return;} pushdown(u); change(ls,x,y,k); change(rs,x,y,k); pushup(tr[u],tr[ls],tr[rs]); } tree query(int u,int x,int y){ //区查 if(x>tr[u].r || y<tr[u].l) return {}; if(x<=tr[u].l&&tr[u].r<=y) return tr[u]; pushdown(u); tree T; //开一个临时节点,存储拼凑结果 pushup(T,query(ls,x,y),query(rs,x,y)); return T; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",a+i); build(1,1,n); for(int i=1;i<=m;i++){ int opt,l,r; scanf("%d%d%d",&opt,&l,&r); ++l,++r; if(opt<3) change(1,l,r,opt); else{ tree t=query(1,l,r); printf("%d\n",opt==3?t.b:t.mb); } } return 0; }