C37 线段树+二分 P4344 [SHOI2015] 脑洞治疗仪

视频链接:223 线段树+二分 [SHOI2015] 脑洞治疗仪_哔哩哔哩_bilibili

 

 

 

Luogu P4344 [SHOI2015] 脑洞治疗仪

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

#define ls u<<1
#define rs u<<1|1
const int N=200005;
int n,m,opt,l0,r0,l1,r1;
struct tree{
  int l,r;
  int sum,lmx,rmx,mx;
  int len,tag;
}tr[N<<2];
//sum:区间1的个数
//lmx:区间左起0的长度
//rmx:区间右起0的长度
// mx:区间0的最长长度
//len:区间的长度
//tag:区间赋值标记,无标记:-1,有标记:0或1

void pushup(tree& u,tree l,tree r){ //上传
  u.sum=l.sum+r.sum;
  u.lmx=l.sum ? l.lmx : l.len+r.lmx;
  u.rmx=r.sum ? r.rmx : r.len+l.rmx;
  u.mx=max(max(l.mx,r.mx),l.rmx+r.lmx);
}
void pd(int u,int k){ //操作区间
  tree& t=tr[u];
  if(k==0){   //区间赋值为0
    t.mx=t.lmx=t.rmx=t.len;
    t.sum=0; t.tag=0;
  }
  else{       //区间赋值为1
    t.mx=t.lmx=t.rmx=0;
    t.sum=t.len; t.tag=1;
  }
}
void pushdown(int u){ //下传
  if(tr[u].tag==0) pd(ls,0),pd(rs,0);
  if(tr[u].tag==1) pd(ls,1),pd(rs,1);
  tr[u].tag=-1;
}
void build(int u,int l,int r){ //建树
  tr[u]={l,r,1,0,0,0,r-l+1,-1};
  if(l==r) return;
  int mid=(l+r)>>1;
  build(ls,l,mid);
  build(rs,mid+1,r);
  pushup(tr[u],tr[ls],tr[rs]);
}
void change(int u,int x,int y,int k){ //区修
  if(x<=tr[u].l&&tr[u].r<=y){pd(u,k);return;}
  pushdown(u);
  if(tr[ls].r>=x)change(ls,x,y,k);
  if(tr[rs].l<=y)change(rs,x,y,k);
  pushup(tr[u],tr[ls],tr[rs]);
}
int q1(int u,int x,int y){ //查询1的个数
  if(x<=tr[u].l&&tr[u].r<=y)return tr[u].sum;
  pushdown(u);
  if(y<tr[rs].l) return q1(ls,x,y);
  if(x>tr[ls].r) return q1(rs,x,y);
  return q1(ls,x,y)+q1(rs,x,y);
}
int q0(int u,int x,int y){ //查询0的个数
  if(x<=tr[u].l&&tr[u].r<=y)
    return tr[u].len-tr[u].sum;
  pushdown(u);
  if(y<tr[rs].l) return q0(ls,x,y);
  if(x>tr[ls].r) return q0(rs,x,y);
  return q0(ls,x,y)+q0(rs,x,y);
}
void work(){
  scanf("%d%d",&l1,&r1);
  int x=q1(1,l0,r0); //查询1的个数
  if(x==0) return;   //去掉会误填1
  change(1,l0,r0,0); //全部变成0
  
  int l=l1,r=r1+1;   //二分答案
  while(l+1<r){
    int m=(l+r)>>1;
    q0(1,l1,m)<=x ? l=m:r=m;
  }
  change(1,l1,l,1); //填上1
}
tree query(int u,int x,int y){ //区查
  if(x<=tr[u].l&&tr[u].r<=y) return tr[u];
  pushdown(u);
  if(y<tr[rs].l) return query(ls,x,y);  
  if(x>tr[ls].r) return query(rs,x,y);
  tree T; //开一个临时节点,存储拼凑结果
  pushup(T,query(ls,x,y),query(rs,x,y));
  return T;
}
int main(){
  scanf("%d%d",&n,&m);
  build(1,1,n);
  while(m--){
    scanf("%d%d%d",&opt,&l0,&r0);
    if(opt==0) change(1,l0,r0,0);
    if(opt==1) work();
    if(opt==2) printf("%d\n",query(1,l0,r0).mx);
  }
  return 0;
}

 

posted @ 2023-09-25 15:47  董晓  阅读(213)  评论(0编辑  收藏  举报