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

视频链接:222 线段树 [SCOI2010] 序列操作_哔哩哔哩_bilibili

 

 

 

Luogu P2572 [SCOI2010] 序列操作

#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;
}

 

posted @ 2023-09-24 21:41  董晓  阅读(310)  评论(0编辑  收藏  举报