[P4344 [SHOI2015] 腦洞治療儀]

liuboom發表於2024-11-11

P4344 [SHOI2015] 腦洞治療儀

說句閒話: 模擬賽因為沒注意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;
}

相關文章