• BZOJ 4592


    4592: [Shoi2015]脑洞治疗仪

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 346  Solved: 147
    [Submit][Status][Discuss]

    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

    HINT

     

    Source

    By 佚名上传

    线段树

    如果不用tag的话会TLE

    一开始ask写错了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #define N 200005
    using namespace std;
    int n,m;
    struct seg
    {
        int l,r;
        int lm,rm,m,s,tag;
        int full;
    }t[N<<2];
    inline seg merge(seg a,seg b)
    {
        seg tmp;tmp.l=a.l;tmp.r=b.r;
        if(a.full)tmp.lm=a.m+b.lm;else tmp.lm=a.lm;
        if(b.full)tmp.rm=a.rm+b.m;else tmp.rm=b.rm;
        if(a.full && b.full)tmp.full=1;else tmp.full=0;
        tmp.m=max(max(a.m,b.m),a.rm+b.lm);
        tmp.s=a.s+b.s; tmp.tag=-1;
        return tmp;
    }
    void paint(int k,int v)
    {
        if(v==1)
        {
            t[k].lm=t[k].rm=t[k].m=t[k].s=0;
            t[k].full=0;
        }
        else 
        {
            t[k].lm=t[k].rm=t[k].m=t[k].s=t[k].r-t[k].l+1;
            t[k].full=1;
        }
        t[k].tag=v;
    //    if(t[k].l==t[k].r)return;
    //    paint(k<<1,v);paint(k<<1|1,v);
    }
    inline void pushup(int k)
    {t[k]=merge(t[k<<1],t[k<<1|1]);}
    inline void pushdown(int k)
    {
        if (t[k].tag!=-1)
        {
            t[k<<1].tag=t[k<<1|1].tag=t[k].tag;
            paint(k<<1,t[k].tag);paint(k<<1|1,t[k].tag);
            t[k].tag=-1;
        }
    }
    void build(int k,int l,int r)
    {
        t[k].l=l;t[k].r=r;
        t[k].lm=t[k].rm=t[k].m=t[k].s=0;
        t[k].tag=-1;t[k].full=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(k<<1,l,mid);build(k<<1|1,mid+1,r);
        pushup(k);
    }
    int query(int k,int x,int y)
    {
        int l=t[k].l,r=t[k].r;
        if(l==x && r==y)return t[k].s;
        pushdown(k);
        int mid=(l+r)>>1;
        if(mid>=y)return query(k<<1,x,y);
        else if(mid<x)return query(k<<1|1,x,y);
        else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y);
    }
    void dig(int k,int x,int y)
    {
        int l=t[k].l,r=t[k].r;
        if(l==x && r==y){paint(k,0);return;}
        pushdown(k);
        int mid=(l+r)>>1;
        if(mid>=y)dig(k<<1,x,y);
        else if(mid<x)dig(k<<1|1,x,y);
        else
        {
            dig(k<<1,x,mid);
            dig(k<<1|1,mid+1,y);
        }
        pushup(k);
    //    printf("%d %d
    ",k,x,y);
    //    printf("%d %d %d %d %d
    ",k,t[k].l,t[k].r,t[k].m,t[k].s);
    }
    void fill(int k,int x,int y,int s)
    {
        if(!s)return;
        int l=t[k].l,r=t[k].r;
        if(l==x && r==y && t[k].s<=s){paint(k,1);return;}
        pushdown(k);
        int mid=(l+r)>>1,lenl;
        if(mid>=y)fill(k<<1,x,y,s);
        else if(mid<x)fill(k<<1|1,x,y,s);
        else
        {
            lenl=query(1,x,mid);
            if(lenl<=s){fill(k<<1,x,mid,lenl);fill(k<<1|1,mid+1,y,s-lenl);}
            else fill(k<<1,x,mid,s);
        }
        pushup(k);
    }
    
    int ask(int k,int x,int y,int p)
    {
        int l=t[k].l,r=t[k].r;
        if (p==-1) if (t[k].rm>=y-x+1) return (y-x+1);else return (t[k].rm);
        else if (p==1) if (t[k].lm>=y-x+1) return y-x+1;else return t[k].lm;
        if(l==x && r==y)return t[k].m;
        if (t[k].tag!=-1)
        {
                t[k<<1].tag=t[k<<1|1].tag=t[k].tag;
                paint(k<<1,t[k].tag);paint(k<<1|1,t[k].tag);
                t[k].tag=-1;
            }     
        int mid=(l+r)>>1;
        if(mid>=y)return ask(k<<1,x,y,0);
        else if(mid<x)return ask(k<<1|1,x,y,0);
        else return max(max(ask(k<<1,x,mid,-1)+ask(k<<1|1,mid+1,y,1),ask(k<<1|1,mid+1,y,0)),ask(k<<1,x,mid,0));
    }
    /*
    void debug()
    {
        for(int k=1;k<=25;k++)
            printf("%d %d %d %d %d
    ",k,t[k].l,t[k].r,t[k].m,t[k].s);
    }
    */
    int main()
    {
        scanf("%d%d",&n,&m);
        build(1,1,n);
    //    debug();
        for(int i=0;i<m;i++)
        {
            int f;
            scanf("%d",&f);
            if(f==0)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                dig(1,x,y);
    //            debug();
            }
            if(f==1)
            {
                int l0,r0,l1,r1;
                scanf("%d%d%d%d",&l0,&r0,&l1,&r1);
                int s=r0-l0+1-query(1,l0,r0);
                dig(1,l0,r0);
    //            debug();
    //            printf("%d
    ********
    ",s);
                fill(1,l1,r1,s);
    //           debug();
            }
            if(f==2)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%d
    ",ask(1,x,y,0));
            }
        }
    //    system("pause");
        return 0;
    }

    感谢lxy

  • 相关阅读:
    PHP is_numeric 检测变量是否为数字或数字字符串
    CSS texttransform实现首个或全部字母大写或小写
    To be a true man
    前辈的话
    做好你自己
    PHP mysql_real_escape_string() 函数
    这些事,我们早就该知道……
    Win7 如何更改用户名
    js或css文件后面跟参数的原因说明
    网页优化插件 YSlow
  • 原文地址:https://www.cnblogs.com/fdfzhyf/p/6435414.html
Copyright © 2020-2023  润新知