[P4344 [SHOI2015] 脑洞治疗仪]

P4344 [SHOI2015] 脑洞治疗仪

P4344 [SHOI2015] 脑洞治疗仪

题目描述

曾经发明了自动刷题机的发明家 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 的问题:在大脑某个区间中最大的连续脑洞区域有多大。

输入格式

第一行两个整数 \(n,m\),表示 SHTSC 的大脑可分为从 \(1\)\(n\) 编号的 \(n\) 个连续区域,有 \(m\) 个操作。

以下 \(m\) 行每行是下列三种格式之一:

  • \(0\quad l\quad r\):SHTSC 挖了一个范围为 \([l, r]\) 的脑洞。
  • \(1\quad l_0\quad r_0\quad l_1\quad r_1\):SHTSC 进行了一次脑洞治疗,用从 \(l_0\)\(r_0\) 的脑组织修补 \(l_1\)\(r_1\) 的脑洞。
  • \(2\quad l\quad r\):SHTSC 询问 \([l, r]\) 区间内最大的脑洞有多大。

上述区间均在 \([1, n]\) 范围内。

输出格式

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

输入输出样例 #1

输入 #1

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

输出 #1

3
3
6
6

说明/提示

对于 \(20\%\) 的数据,\(n, m \leq 100\)
对于 \(50\%\) 的数据,\(n, m \leq 20000\)
对于 \(100\%\) 的数据,\(n, m \leq 200000\)

说句闲话: 模拟赛因为没注意push_up痛失70pts

Solution:

感觉比较好写的线段树,维护几个变量:
\(lmx,rmx,mx,cnt\) ,lmx表示该区间从左端点开始的最长连续脑洞的长度,rmx,mx类似.cnt表示该区间内有多少个点是0

然后注意一下push_up:

void push_up(Tree &T,Tree L,Tree R,int l,int r)
{
    T.lmx=L.lmx,T.rmx=R.rmx;
    if(L.lmx==L.len)T.lmx+=R.lmx;
    if(R.rmx==R.len)T.rmx+=L.rmx;
    T.mx=max(L.mx,R.mx);
    T.mx=max(T.mx,L.rmx+R.lmx);
    T.cnt=L.cnt+R.cnt;
    T.len=L.len+R.len;
}

由于本人实现比较抽象,所以当push_up需要用来统计答案时,一定要对答案的l,r进行正确的赋值与更新

然后这题就做完了

Code:

#include<bits/stdc++.h>
const int N=2e5+5;
using namespace std;
//Segment_Tree
#define ls x<<1
#define rs x<<1|1
struct Tree{
    int lmx,rmx,mx,tag,cnt,len;
}t[N<<2];
void push_up(Tree &T,Tree L,Tree R,int l,int r)
{
    T.lmx=L.lmx,T.rmx=R.rmx;
    if(L.lmx==L.len)T.lmx+=R.lmx;
    if(R.rmx==R.len)T.rmx+=L.rmx;
    T.mx=max(L.mx,R.mx);
    T.mx=max(T.mx,L.rmx+R.lmx);
    T.cnt=L.cnt+R.cnt;
    T.len=L.len+R.len;
}
void push_down(int x,int l,int r)
{
    if(t[x].tag==-1)return;
    int mid=l+r>>1;int len1=mid-l+1,len2=r-(mid+1)+1;
    int tag=t[x].tag;
    t[ls].cnt=t[ls].lmx=t[ls].mx=t[ls].rmx=len1*tag;
    t[rs].cnt=t[rs].lmx=t[rs].mx=t[rs].rmx=len2*tag;
    t[ls].tag=t[rs].tag=tag;
    //<<"push_down:"<<l<<" "<<r<<" "<<t[x].tag<<"="<<t[ls].cnt<<" "<<t[rs].cnt<<"\n";
    t[x].tag=-1;
}
void build(int x,int l,int r)
{
    t[x].len=r-l+1;
    t[x].cnt=t[x].lmx=t[x].rmx=t[x].mx=0;
    t[x].tag=-1;
    if(l==r)return;
    int mid=l+r>>1;
    build(ls,l,mid);build(rs,mid+1,r);
}
void get(int x,int l,int r,int L,int R,int &res)
{
    if(L<=l&&r<=R)
    {
        res+=r-l+1-t[x].cnt;
        t[x].cnt=t[x].lmx=t[x].mx=t[x].rmx=r-l+1;
        t[x].tag=1;
        //<<"get:"<<l<<" "<<r<<"="<<t[x].lmx<<" "<<t[x].rmx<<"=="<<t[x].mx<<" cnt:"<<t[x].cnt<<" tag:"<<t[x].tag<<"\n";
        return ;
    }
    int mid=l+r>>1;
    push_down(x,l,r);
    if(L<=mid)get(ls,l,mid,L,R,res);
    if(mid<R) get(rs,mid+1,r,L,R,res);
    push_up(t[x],t[ls],t[rs],l,r);
    //<<"get:"<<l<<" "<<r<<"="<<t[x].lmx<<" "<<t[x].rmx<<"=="<<t[x].mx<<" cnt:"<<t[x].cnt<<" tag:"<<t[x].tag<<"\n";

}
void ask(int x,int l,int r,int L,int R,int &res)
{
    if(R<L)return ;
    //<<"ask:"<<l<<" "<<r<<" "<<L<<" "<<R<<"="<<t[x].cnt<<"\n";
    if(L<=l&&r<=R)
    {
        res+=t[x].cnt;
        return;
    }
    int mid=l+r>>1;
    push_down(x,l,r);
    if(L<=mid)ask(ls,l,mid,L,R,res);
    if(mid<R) ask(rs,mid+1,r,L,R,res);
}
int find(int x,int l,int r,int k)
{
    if(l==r)
    {
        return l;
    }
    int mid=l+r>>1;
    push_down(x,l,r);
    if(k>t[ls].cnt) return find(rs,mid+1,r,k-t[ls].cnt);
    else return find(ls,l,mid,k);
}
void fix(int x,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)
    {
        t[x].cnt=t[x].tag=0;
        t[x].lmx=t[x].mx=t[x].rmx=0;
        return ;
    }
    int mid=l+r>>1;
    push_down(x,l,r);
    if(L<=mid)fix(ls,l,mid,L,R);
    if(mid<R) fix(rs,mid+1,r,L,R);
    push_up(t[x],t[ls],t[rs],l,r);
}
void query(int x,int l,int r,int L,int R,Tree &res)
{
    if(L<=l&&r<=R)
    {
        //<<l<<" "<<r<<"="<<t[x].cnt<<"\n";
        push_up(res,res,t[x],l,r);
        return;
    }
    int mid=l+r>>1;
    push_down(x,l,r);
    if(L<=mid)query(ls,l,mid,L,R,res);
    if(mid<R) query(rs,mid+1,r,L,R,res);
}
int n,m;
void work()
{
    cin>>n>>m;
    build(1,1,n);
    for(int i=1,opt,l,r,L,R,k;i<=m;i++)
    {
        k=0;
        scanf("%d%d%d",&opt,&l,&r);
        if(opt==0)
        {
            get(1,1,n,l,r,k);
        }
        if(opt==1)
        {
            scanf("%d%d",&L,&R);
            get(1,1,n,l,r,k);
            int pre=0;
            ask(1,1,n,1,L-1,pre);
            k+=pre;
            if(k==0)continue;
            int pos=min(find(1,1,n,k),R);
            //<<"fix:"<<pre<<" "<<k-pre<<" "<<pos<<"\n";
            fix(1,1,n,L,pos);
        }
        if(opt==2)
        {
            Tree ans=(Tree){0,0,0,0,0,0};
            query(1,1,n,l,r,ans);
            printf("%d\n",ans.mx);
        }
    }
}
int main()
{
    //freopen("instrument.in","r",stdin);
    //freopen("instrument.out","w",stdout);
    work();
    return 0;
}
posted @ 2024-11-11 18:44  liuboom  阅读(19)  评论(0)    收藏  举报