bzoj4592 脑洞治疗仪 线段树

15 篇文章 0 订阅

Description

曾经发明了自动刷题机的发明家SHTSC又公开了他的新发明:脑洞治疗仪–一种可以治疗他因为发明而日益增大的脑洞的神秘装置。
为了简单起见,我们将大脑视作一个01序列。1代表这个位置的脑组织正常工作,0代表这是一块脑洞。
1 0 1 0 0 0 1 1 1 0
脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中。
(所以脑洞治疗仪是脑洞的治疗仪?)
例如,用上面第8号位置到第10号位置去修补第1号位置到第4号位置的脑洞。我们就会得到:
1 1 1 1 0 0 1 0 0 0
如果再用第1号位置到第4号位置去修补第8号位置到第10号位置:
0 0 0 0 0 0 1 1 1 1
这是因为脑洞治疗仪会把多余出来的脑组织直接扔掉。
如果再用第7号位置到第10号位置去填补第1号位置到第6号位置:
1 1 1 1 0 0 0 0 0 0
这是因为如果新脑洞挖出来的脑组织不够多,脑洞治疗仪仅会尽量填补位置比较靠前的脑洞。
假定初始时SHTSC并没有脑洞,给出一些挖脑洞和脑洞治疗的操作序列,你需要即时回答SHTSC的问题:
在大脑某个区间中最大的连续脑洞区域有多大。
Input

第一行两个整数n,m。表示SHTSC的大脑可分为从1到n编号的n个连续区域。有m个操作。
以下m行每行是下列三种格式之一。
0 l r :SHTSC挖了一个从l到r的脑洞。
1 l0 r0 l1 r2 :SHTSC进行了一次脑洞治疗,用从l0到r0的脑组织修补l1到r1的脑洞。
2 l r :SHTSC询问l到r这段区间最大的脑洞有多大。
n,m <=200000,1<=l<=r<=n
Output

对于每个询问,输出一行一个整数,表示询问区间内最大连续脑洞区域有多大。
Sample Input

10 10

0 2 2

0 4 6

0 10 10

2 1 10

1 8 10 1 4

2 1 10

1 1 4 8 10

2 1 10

1 7 10 1 6

2 1 10

Sample Output

3

3

6

6


这里写图片描述

釜山行确实好看…推荐大家去看一下

这道题坑爹啊,一开始自作聪明,1操作没有去二分而靠自己特判,wa的糊里糊涂.,调了半天.

这道题线段树要维护的东西有,本区间的:最左/右边的最长连续零lc rc,零的总个数all,整个区间的最长连续零cmax以及区间的标记flag,区间的长度len.
每次pushdown,update的时候更新一下这些东西即可.

对于1操作,我们先找出挖掉区间的1的个数(区间长度-零的总个数),记得要立马把这段区间赋成0,因为可能这段要挖掉的区间就在待填补区间里,再统计需填补区间的脑洞个数,如果大于的话直接整个区间赋成1,小于的话就二分一下待填补区间,找到L(待填补区间的)到mid的脑洞个数刚好等于需挖掉的区间的可以用来的填补的脑组织(1)个数,就break.直接把L到mid的区间赋成1,即可.

/**************************************************************
    Problem: 4592
    User: MaxMercer
    Language: C++
    Result: Accepted
    Time:9712 ms
    Memory:25924 kb
****************************************************************/

#include<stdio.h>
const int maxn=200001;
int t1,t2,L,R,opt,n,m,fix;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    register int x=0,f=1;
    register char ch=nc();
    while(ch<'0'||ch>'9'){if(ch=='-')f*=-1;ch=nc();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=nc();
    return f*x;
}
inline int max(int x,int y){if(x>y) return x;else return y;}
inline int min(int x,int y){if(x<y) return x;else return y;}
struct node{
    node *ls,*rs;
    int cmax,lc,rc,flag,len,all;
    void pushdown(){
         if(flag==1){
            ls->cmax=ls->lc=ls->rc=ls->all=ls->len;
            ls->flag=1;
            rs->cmax=rs->lc=rs->rc=rs->all=rs->len;
            rs->flag=1;
         }
         if(flag==2){
            ls->cmax=ls->lc=ls->rc=ls->all=0;
            ls->flag=2;
            rs->cmax=rs->lc=rs->rc=rs->all=0;
            rs->flag=2;
         }
         flag=0;
    }
    void update(){
         if(ls->cmax==ls->len) lc=ls->len+rs->lc;
         else lc=ls->lc;
         if(rs->cmax==rs->len) rc=rs->len+ls->rc;
         else rc=rs->rc;
         all=ls->all+rs->all;
         cmax=max(ls->cmax,rs->cmax);
         cmax=max(cmax,ls->rc+rs->lc);
    }
}pool[maxn*4],*root,*tail=pool;
node *build(int lf,int rg){
    node *bt=++tail;
    if(lf==rg) {bt->len=1;bt->cmax=bt->lc=bt->rc=bt->flag=bt->all=0;return bt;}
    int mid=(lf+rg)>>1;
    bt->ls=build(lf,mid);
    bt->rs=build(mid+1,rg);
    bt->cmax=bt->lc=bt->rc=bt->flag=bt->all=0;
    bt->len=rg-lf+1;
    return bt;
}
void modify(node *bt,int lf,int rg,int L,int R,int val){
    if(L<=lf&&rg<=R){
       if(!val) bt->cmax=bt->lc=bt->rc=bt->all=rg-lf+1,bt->flag=1;
       else  bt->cmax=bt->lc=bt->rc=bt->all=0,bt->flag=2;
       return;
    }
    int mid=(lf+rg)>>1;
    bt->pushdown();
    if(L<=mid) modify(bt->ls,lf,mid,L,R,val);
    if(R>mid)  modify(bt->rs,mid+1,rg,L,R,val);
    bt->update();
}
int query(node *bt,int lf,int rg,int L,int R){
    if(L<=lf&&rg<=R) return bt->cmax;
    int mid=(lf+rg)>>1;
    bt->pushdown();
    int r1=0,r2=0,ans=0;
    if(L<=mid) r1=query(bt->ls,lf,mid,L,R);
    if(R>mid) r2=query(bt->rs,mid+1,rg,L,R);
    if(r1&&r2){
       if(mid-L+1<bt->ls->rc) ans+=mid-L+1;
       else ans+=bt->ls->rc;
       if(R-mid<bt->rs->lc) ans+=R-mid;
       else ans+=bt->rs->lc; 
    }
    ans=max(ans,max(r1,r2));
    bt->update();
    return ans;
}
int query_all(node *bt,int lf,int rg,int L,int R){
    if(L<=lf&&rg<=R) return bt->all;
    int mid=(lf+rg)>>1;
    bt->pushdown();
    int rt=0;
    if(L<=mid) rt+=query_all(bt->ls,lf,mid,L,R);
    if(R>mid) rt+=query_all(bt->rs,mid+1,rg,L,R);
    return rt;
}
int main(){
    n=read(),m=read();
    root=build(1,n);
    while(m--){
      opt=read();
      if(!opt) L=read(),R=read(),modify(root,1,n,L,R,0);
      if(opt==1){
         L=read(),R=read();
         t1=R-L+1-query_all(root,1,n,L,R),modify(root,1,n,L,R,0);
         L=read(),R=read();
         t2=query_all(root,1,n,L,R);
         int l=L,r=R;
         if(!t1||!t2) continue;
         if(t1>=t2) modify(root,1,n,L,R,1);
         else{
         while(1){
            int mid=(l+r)>>1;
            if(query_all(root,1,n,L,mid)>t1){r=mid-1;continue;}
            if(query_all(root,1,n,L,mid)<t1){l=mid+1;continue;}
            modify(root,1,n,L,mid,1);break;
         }
         }
      }
      if(opt==2) L=read(),R=read(),printf("%d\n",query(root,1,n,L,R));
    }
}


这里用了读入优化无法手工输入,要测试代码的话用这份.再附上一份随机数据生成代码.

#include<stdio.h>
const int maxn=200001;
int t1,t2,L,R,opt,n,m,fix;
inline int max(int x,int y){if(x>y) return x;else return y;}
inline int min(int x,int y){if(x<y) return x;else return y;}
struct node{
    node *ls,*rs;
    int cmax,lc,rc,flag,len,all;
    void pushdown(){
         if(flag==1){
            ls->cmax=ls->lc=ls->rc=ls->all=ls->len;
            ls->flag=1;
            rs->cmax=rs->lc=rs->rc=rs->all=rs->len;
            rs->flag=1;
         }
         if(flag==2){
            ls->cmax=ls->lc=ls->rc=ls->all=0;
            ls->flag=2;
            rs->cmax=rs->lc=rs->rc=rs->all=0;
            rs->flag=2;
         }
         flag=0;
    }
    void update(){
         if(ls->cmax==ls->len) lc=ls->len+rs->lc;
         else lc=ls->lc;
         if(rs->cmax==rs->len) rc=rs->len+ls->rc;
         else rc=rs->rc;
         all=ls->all+rs->all;
         cmax=max(ls->cmax,rs->cmax);
         cmax=max(cmax,ls->rc+rs->lc);
    }
}pool[maxn*4],*root,*tail=pool;
node *build(int lf,int rg){
    node *bt=++tail;
    if(lf==rg) {bt->len=1;bt->cmax=bt->lc=bt->rc=bt->flag=bt->all=0;return bt;}
    int mid=(lf+rg)>>1;
    bt->ls=build(lf,mid);
    bt->rs=build(mid+1,rg);
    bt->cmax=bt->lc=bt->rc=bt->flag=bt->all=0;
    bt->len=rg-lf+1;
    return bt;
}
void modify(node *bt,int lf,int rg,int L,int R,int val){
    if(L<=lf&&rg<=R){
       if(!val) bt->cmax=bt->lc=bt->rc=bt->all=rg-lf+1,bt->flag=1;
       else  bt->cmax=bt->lc=bt->rc=bt->all=0,bt->flag=2;
       return;
    }
    int mid=(lf+rg)>>1;
    bt->pushdown();
    if(L<=mid) modify(bt->ls,lf,mid,L,R,val);
    if(R>mid)  modify(bt->rs,mid+1,rg,L,R,val);
    bt->update();
}
int query(node *bt,int lf,int rg,int L,int R){
    if(L<=lf&&rg<=R) return bt->cmax;
    int mid=(lf+rg)>>1;
    bt->pushdown();
    int r1=0,r2=0,ans=0;
    if(L<=mid) r1=query(bt->ls,lf,mid,L,R);
    if(R>mid) r2=query(bt->rs,mid+1,rg,L,R);
    if(r1&&r2){
       if(mid-L+1<bt->ls->rc) ans+=mid-L+1;
       else ans+=bt->ls->rc;
       if(R-mid<bt->rs->lc) ans+=R-mid;
       else ans+=bt->rs->lc; 
    }
    ans=max(ans,max(r1,r2));
    bt->update();
    return ans;
}
int query_all(node *bt,int lf,int rg,int L,int R){
    if(L<=lf&&rg<=R) return bt->all;
    int mid=(lf+rg)>>1;
    bt->pushdown();
    int rt=0;
    if(L<=mid) rt+=query_all(bt->ls,lf,mid,L,R);
    if(R>mid) rt+=query_all(bt->rs,mid+1,rg,L,R);
    return rt;
}
inline const int read(){
    register int f=1,x=0;
    register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return f*x;
}
int main(){
    n=read(),m=read();
    root=build(1,n);
    while(m--){
      opt=read();
      if(!opt) L=read(),R=read(),modify(root,1,n,L,R,0);
      if(opt==1){
         L=read(),R=read();
         t1=R-L+1-query_all(root,1,n,L,R),modify(root,1,n,L,R,0);
         L=read(),R=read();
         t2=query_all(root,1,n,L,R);
         int l=L,r=R;
         if(!t1||!t2) continue;
         if(t1>=t2) modify(root,1,n,L,R,1);
         else{
         while(1){
            int mid=(l+r)>>1;
            if(query_all(root,1,n,L,mid)>t1){r=mid-1;continue;}
            if(query_all(root,1,n,L,mid)<t1){l=mid+1;continue;}
            modify(root,1,n,L,mid,1);break;
         }
         }
      }
      if(opt==2) L=read(),R=read(),printf("%d\n",query(root,1,n,L,R));
    }
}

可自己修改一下数据(注意修改rand取余的数),方便你比较一下.

#include<stdio.h>
#include<ctime>
#include<cstdlib>
#include<algorithm>
using namespace std;
int L,opt,R;
int main(){
    srand(time(0));
    freopen("txt.out","w",stdout);
    printf("100 100\n");
    for(register int i=1;i<=100;i++){
       opt=rand()%3;
       printf("%d ",opt);
       if(!opt) {L=rand()%101;if(!L)L++;R=rand()%101;if(!R)R++;if(L>R) swap(L,R);printf("%d %d\n",L,R);} 
       if(opt==1) {L=rand()%101;if(!L)L++;R=rand()%101;if(!R)R++;if(L>R) swap(L,R);printf("%d %d ",L,R);L=rand()%101;if(!L)L++;R=rand()%101;if(!R)R++;if(L>R) swap(L,R);printf("%d %d\n",L,R);} 
       if(opt==2) {L=rand()%101;if(!L)L++;R=rand()%101;if(!R)R++;if(L>R) swap(L,R);printf("%d %d\n",L,R);} 
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值