• 【SHOI2015】脑洞治疗仪 题解 (线段树)


    题目链接

    题目大意:给定一个只含$0$和$1$的序列。有三种操作:1.把$[l,r]$内所有数改为$0$;2.把$[l,r]$内所有$1$拿走来填$[l',r']$内所有$0$。多了丢掉,少了优先从左开始填;3.查询$[l,r]$内最长的$0$串。

    ---------------------------

    一眼能看出来考最大子段和。但是代码好难调啊QAQ

    对于一段序列,我们要维护$4$个东西:$ls,rs,ms,s$,分别为从左端点开始最长的$0$串,从右端点开始最长的$0$串,序列内最长的$0$串,序列和。

    维护最大子段和,无非就两种情况:跨过$mid$和没有跨过$mid$。注意在维护$ms$的时候有三种情况:左儿子的$ms$,右儿子的$ms$,左儿子$rs$加右儿子$ls$。也可以翻我之前的博客。

    对于区间修改我们维护一个$lazy$,在$pushdown$的时候维护一下序列就好。

    最后说一下$2$操作。我们注意到在一段序列内的和是非严格单调递增的。所以要确定我们填的这个区间,我们只需二分一下这个右端点即可。

    然后就是恶心人的调代码时间了。压过行后也有130行……

    时间复杂度$O(nlog^2 n)$

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=200005;
    int n,m;
    struct node
    {
        int ms,ls,rs,s,lazy,l,r,len;
    }tree[maxn*4];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void pushup(int index)
    {
        tree[index].s=tree[index*2].s+tree[index*2+1].s;
        if (tree[index*2].len==tree[index*2].ls)
            tree[index].ls=tree[index*2].len+tree[index*2+1].ls;
        else tree[index].ls=tree[index*2].ls;
        if (tree[index*2+1].len==tree[index*2+1].rs)
            tree[index].rs=tree[index*2+1].len+tree[index*2].rs;
        else tree[index].rs=tree[index*2+1].rs;
        tree[index].ms=max(max(tree[index*2].ms,tree[index*2+1].ms),tree[index*2].rs+tree[index*2+1].ls);
    } 
    inline void build(int index,int l,int r)
    {
        tree[index].l=l;tree[index].r=r;
        tree[index].len=r-l+1;
        tree[index].lazy=-1;
        if (l==r){tree[index].s=1;tree[index].ls=tree[index].rs=tree[index].ms=0;return;}
        int mid=(l+r)>>1;
        build(index*2,l,mid);
        build(index*2+1,mid+1,r);
        pushup(index);
    }
    inline void pushdown(int index,int l,int r)//ms,ls,rs,s,lazy
    {
        if (tree[index].lazy==0)
        {
            tree[index*2].lazy=tree[index*2+1].lazy=tree[index*2].s=tree[index*2+1].s=0;
            tree[index*2].ms=tree[index*2].ls=tree[index*2].rs=tree[index*2].len;
            tree[index*2+1].ms=tree[index*2+1].ls=tree[index*2+1].rs=tree[index*2+1].len;
        }
        if (tree[index].lazy==1)
        {
            tree[index*2].lazy=tree[index*2+1].lazy=1;
            tree[index*2].s=tree[index*2].len;
            tree[index*2+1].s=tree[index*2+1].len;
            tree[index*2].ms=tree[index*2].ls=tree[index*2].rs=0;
            tree[index*2+1].ms=tree[index*2+1].ls=tree[index*2+1].rs=0;
        }
        tree[index].lazy=-1;
    }
    inline void update(int index,int l,int r,int ql,int qr,int k)
    {
        if (ql<=l&&r<=qr)
        {
            tree[index].s=tree[index].len*k;
            if (k==0) tree[index].ls=tree[index].rs=tree[index].ms=tree[index].len,tree[index].lazy=0;
            else tree[index].ls=tree[index].rs=tree[index].ms=0,tree[index].lazy=1;
            return;
        }
        pushdown(index,l,r);
        int mid=(l+r)>>1;
        if (ql<=mid) update(index*2,l,mid,ql,qr,k);
        if (qr>mid) update(index*2+1,mid+1,r,ql,qr,k);
        pushup(index);
    }
    inline int querysum(int index,int l,int r,int ql,int qr)
    {
        if (ql<=l&&r<=qr) return tree[index].s;
        pushdown(index,l,r);
        int mid=(l+r)>>1,res=0;
        if (ql<=mid) res+=querysum(index*2,l,mid,ql,qr);
        if (qr>mid) res+=querysum(index*2+1,mid+1,r,ql,qr);
        return res;
    }
    inline int queryrest(int index,int l,int r,int ql,int qr)
    {
        if (ql<=l&&r<=qr) return tree[index].len-tree[index].s;
        pushdown(index,l,r);
        int mid=(l+r)>>1,res=0;
        if (ql<=mid) res+=queryrest(index*2,l,mid,ql,qr);
        if (qr>mid) res+=queryrest(index*2+1,mid+1,r,ql,qr);
        return res;
    }
    inline int querymax(int index,int l,int r,int ql,int qr)
    {
        if (ql<=l&&r<=qr) return tree[index].ms;
        pushdown(index,l,r);
        int mid=(l+r)>>1,res=0;
        if (tree[index*2].r<ql) return querymax(index*2+1,mid+1,r,ql,qr);
        else if (qr<tree[index*2+1].l) return querymax(index*2,l,mid,ql,qr);
        else{
            res=max(querymax(index*2,l,mid,ql,qr),querymax(index*2+1,mid+1,r,ql,qr));
            res=max(res,min(tree[index*2].rs,tree[index*2+1].l-ql)+min(tree[index*2+1].ls,qr-tree[index*2].r));
        }
        return res;
    }
    inline void work(int l0,int r0)
    {
        int l1=read(),r1=read();
        int x=querysum(1,1,n,l0,r0);
        if (x==0) return;
        update(1,1,n,l0,r0,0);
        int l=l1,r=r1,ans;
        while(l<=r){
            int mid=(l+r)>>1;
            if(queryrest(1,1,n,l1,mid)<=x)l=mid+1,ans=mid;
            else r=mid-1;
        }
        update(1,1,n,l1,ans,1);
    }
    int main()
    {
        n=read(),m=read();
        build(1,1,n);
        for (int i=1;i<=m;i++)
        {
            int opt=read(),l=read(),r=read();
            if (opt==0) update(1,1,n,l,r,0);
            else if (opt==2) printf("%d
    ",querymax(1,1,n,l,r));
            else work(l,r);
        }
        return 0;
    }
  • 相关阅读:
    个人推荐网上商店
    vs 安装程序制作
    this linker was not configured to use sysroots和C compiler cannot create executables的解决办法
    将asihttprequest编译后的目标文件打包
    cygwin下的gcc4.7.1编译心得
    给ubuntu12.04换3.4.6的内核
    boost::asio::streambuf相关的操作方法
    应用boost库serialize标准库里的map
    cygwin下gdb7.4编译
    sql server存储过程分页,支持cte
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13435727.html
Copyright © 2020-2023  润新知