• [BZOJ 4592][Shoi2015]脑洞治疗仪(线段树)


    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的问题:
    在大脑某个区间中最大的连续脑洞区域有多大。

    Solution

    (题面好可怕)

    思路应该还挺明显的线段树,补脑洞的过程中可以返回用了多少脑组织的值以便于优先补左面

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #define MAXN 200005
    using namespace std;
    int n,m;
    struct Node
    {
        int l,r,num,lnum,rnum,maxnum;
        int lazy;
        Node():num(0),lnum(0),rnum(0),maxnum(0),lazy(0){}
    }t[MAXN*4];
    int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    Node operator + (const Node& a,const Node& b)
    {
        Node c;
        c.lnum=(a.lnum==a.r-a.l+1)?a.lnum+b.lnum:a.lnum;
        c.rnum=(b.rnum==b.r-b.l+1)?b.rnum+a.rnum:b.rnum;
        c.num=a.num+b.num;
        c.maxnum=max(a.maxnum,b.maxnum);
        c.maxnum=max(c.maxnum,a.rnum+b.lnum);
        c.l=a.l;c.r=b.r;
        return c;
    }
    void build(int idx,int l,int r)
    {
        t[idx].l=l,t[idx].r=r;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(idx<<1,l,mid),build(idx<<1|1,mid+1,r);
    }
    void pushdown(int idx)
    {
        if(t[idx].l==t[idx].r)return;
        if(t[idx].lazy==1)
        {
            t[idx].lazy=0;
            t[idx<<1].lazy=t[idx<<1|1].lazy=1;
            t[idx<<1].num=t[idx<<1].lnum=t[idx<<1].rnum=t[idx<<1].maxnum=t[idx<<1].r-t[idx<<1].l+1;
            t[idx<<1|1].num=t[idx<<1|1].lnum=t[idx<<1|1].rnum=t[idx<<1|1].maxnum=t[idx<<1|1].r-t[idx<<1|1].l+1;
        }
        else if(t[idx].lazy==2)
        {
            t[idx].lazy=0;
            t[idx<<1].lazy=t[idx<<1|1].lazy=2;
            t[idx<<1].num=t[idx<<1].lnum=t[idx<<1].rnum=t[idx<<1].maxnum=0;
            t[idx<<1|1].num=t[idx<<1|1].lnum=t[idx<<1|1].rnum=t[idx<<1|1].maxnum=0;
        }
    }
    void pushup(int idx)
    {
        if(t[idx].l==t[idx].r)return;
        t[idx].lnum=(t[idx<<1].lnum==t[idx<<1].r-t[idx<<1].l+1)?t[idx<<1].lnum+t[idx<<1|1].lnum:t[idx<<1].lnum;
        t[idx].rnum=(t[idx<<1|1].rnum==t[idx<<1|1].r-t[idx<<1|1].l+1)?t[idx<<1|1].rnum+t[idx<<1].rnum:t[idx<<1|1].rnum;
        t[idx].num=t[idx<<1].num+t[idx<<1|1].num;
        t[idx].maxnum=max(t[idx<<1].maxnum,t[idx<<1|1].maxnum);
        t[idx].maxnum=max(t[idx].maxnum,t[idx<<1].rnum+t[idx<<1|1].lnum);
    }
    void clear(int idx,int l,int r)
    {
        if(l<=t[idx].l&&r>=t[idx].r)
        {
            t[idx].num=t[idx].lnum=t[idx].rnum=t[idx].maxnum=t[idx].r-t[idx].l+1;
            t[idx].lazy=1;return;
        }
        pushdown(idx);
        int mid=(t[idx].l+t[idx].r)>>1;
        if(r<=mid)clear(idx<<1,l,r);
        else if(l>mid)clear(idx<<1|1,l,r);
        else clear(idx<<1,l,r),clear(idx<<1|1,l,r);
        pushup(idx);
    }
    int add(int idx,int l,int r,int x)//返回用了多少脑组织 
    {
        if(x<=0)return 0;
        if(!t[idx].num)return 0;
        int p,q;
        if(l<=t[idx].l&&r>=t[idx].r)
        {
            p=t[idx].num;
            if(p==t[idx].r-t[idx].l+1&&p<=x)//都是naodong 补好 
            {
                x-=p;
                t[idx].num=t[idx].lnum=t[idx].rnum=t[idx].maxnum=0;
                t[idx].lazy=2;return p;
            }
        }
        pushdown(idx);
        int mid=(t[idx].l+t[idx].r)>>1;
        if(r<=mid)p=add(idx<<1,l,r,x);
        else if(l>mid)p=add(idx<<1|1,l,r,x);
        else 
        {    
            p=add(idx<<1,l,r,x);
            q=add(idx<<1|1,l,r,x-p);
            p+=q;
        }
        pushup(idx);
        return p;
    }
    int querynum(int idx,int l,int r)
    {
        if(!t[idx].num)return 0;
        if(l<=t[idx].l&&r>=t[idx].r)return t[idx].num;
        pushdown(idx);
        int mid=(t[idx].l+t[idx].r)>>1;
        if(r<=mid)return querynum(idx<<1,l,r);
        else if(l>mid)return querynum(idx<<1|1,l,r);
        else return querynum(idx<<1,l,r)+querynum(idx<<1|1,l,r);
    }
    Node querymax(int idx,int l,int r)
    {
        if(l<=t[idx].l&&r>=t[idx].r)return t[idx];
        pushdown(idx);
        int mid=(t[idx].l+t[idx].r)>>1;
        if(r<=mid)return querymax(idx<<1,l,r);
        else if(l>mid)return querymax(idx<<1|1,l,r);
        else return querymax(idx<<1,l,r)+querymax(idx<<1|1,l,r);
    }
    int main()
    {
        n=read(),m=read();
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            int opt=read(),l0,r0,l1,r1;
            if(opt==0)
            {
                l0=read(),r0=read();
                clear(1,l0,r0);
            }
            else if(opt==1)
            {
                l0=read(),r0=read(),l1=read(),r1=read();
                int t=r0-l0+1-querynum(1,l0,r0);
                clear(1,l0,r0);
                add(1,l1,r1,t);
            }
            else
            {
                l0=read(),r0=read();
                printf("%d
    ",querymax(1,l0,r0).maxnum);
            }
        }
        return 0;
    } 
  • 相关阅读:
    最短路径之spfa
    最短路径之Bellman-Ford——解决负权边
    最短路径之Floyd-Warshall算法
    图上最短路径问题
    它们其实都是图(二分图)
    记忆化结果再利用 进一步探讨递推关系
    leetcode 376. 摆动序列 java
    leetcode 368. 最大整除子集 java
    leetcode 96. 不同的二叉搜索树 java
    leetcode 454. 四数相加 II java
  • 原文地址:https://www.cnblogs.com/Zars19/p/6902587.html
Copyright © 2020-2023  润新知