[SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)

Posted ztz11

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)相关的知识,希望对你有一定的参考价值。

题目描述:

曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置。

为了简单起见,我们将大脑视作一个 01 序列。11代表这个位置的脑组织正常工作,00代表这是一块脑洞。

1      0      1      0      0      0      1      1      1      0

脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中。(所以脑洞治疗仪是脑洞的治疗仪?)

例如,用上面第88号位置到第1010号位置去修补第11号位置到第44号位置的脑洞,我们就会得到:

1      1      1      1      0      0      1      0      0      0

如果再用第11号位置到第44号位置去修补第88号位置到第1010号位置:

0      0      0      0      0      0      1      1      1      1

这是因为脑洞治疗仪会把多余出来的脑组织直接扔掉。

如果再用第77号位置到第1010号位置去填补第11号位置到第66号位置:

1      1      1      1      0      0      0      0      0      0

这是因为如果新脑洞挖出来的脑组织不够多,脑洞治疗仪仅会尽量填补位置比较靠前的脑洞。

假定初始时 SHTSC 并没有脑洞,给出一些挖脑洞和脑洞治疗的操作序列,你需要即时回答 SHTSC 的问题:在大脑某个区间中最大的连续脑洞区域有多大。

输入输出格式

输入格式:

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

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

0 l r:SHTSC 挖了一个范围为[l,r]的脑洞。

1 (l_0) (r_0) (l_1) (r_1):SHTSC 进行了一次脑洞治疗,用从(l_0)(r_0) 的脑组织修补(l_1)(r_1) 的脑洞。

2 (l) (r):SHTSC 询问([l,r])区间内最大的脑洞有多大。

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

输出格式:

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

思路

很多题解都提到了GSS系列的最大连续子段和问题,那我就不说了,我只说这道题中我用到的一些奇妙的解法

1.反着定义

这道题要求的是最大连续0的长度,那么用最大子段和的话如果你按1走统计的就不是0,而是1,我们可以将1定义为-inf,0定义为1,再跑最大子段和即可

2.分开存

gss中要存一个区间和sum,但由于上面的定义形式,这玩意儿显然不能表示0(或1)的数量,我们可以用一个mix,专门存0或1的数量

大体思路:

0.首先,给1节点打上-inf的lazy标记,表示没有脑洞

1.对于0操作,区间覆盖,打lazy标记后直接修改即可

2.对于2操作,GSS标准查询即可

3.对于1操作,先求出l1,r1的脑组织数,再全挖成脑洞,之后填进l2,r2去即可(函数写成int式,优先填左区间,填完后返回剩余脑洞数)

代码:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define rii register int i
#define rij register int j
#define rs 262144
#define int long long
using namespace std;
struct tree{
    long long lmax,rmax,sum,lazy,maxn,mix;
}x[1000005];
int n,m,p;
void pushdown(int nl,int nr,long long val,int bh)
{
    int mid=(nl+nr)/2;
    long long cd=mid-nl+1;
    x[bh*2].lazy=val;
    x[bh*2].lmax=val*cd;
    x[bh*2].rmax=val*cd;
    x[bh*2].sum=val*cd;
    x[bh*2].maxn=val*cd;
    x[bh*2].mix=(val%2)*cd;
    x[bh*2+1].mix=(val%2)*cd;
    x[bh*2+1].lazy=val;
    x[bh*2+1].lmax=val*cd;
    x[bh*2+1].rmax=val*cd;
    x[bh*2+1].sum=val*cd;
    x[bh*2+1].maxn=val*cd;
    x[bh].lazy=0;
}
void fg(int l,int r,int nl,int nr,int bh)
{
    if(l<nl)
    {
        l=nl;
    }
    if(r>nr)
    {
        r=nr;
    }
    if(x[bh].lazy==1)
    {
        return;
    }
    if(x[bh].lazy==-100000)
    {
        pushdown(nl,nr,x[bh].lazy,bh);
    }
    if(l==nl&&r==nr)
    {
        x[bh].lazy=1;
        x[bh].sum=(r-l+1);
        x[bh].lmax=(r-l+1);
        x[bh].rmax=(r-l+1);
        x[bh].maxn=(r-l+1);
        x[bh].mix=(r-l+1);
        return;
    }
    int mid=(nl+nr)/2;
    if(l<=mid)
    {
        fg(l,r,nl,mid,bh*2);
    }
    if(r>=mid+1)
    {
        fg(l,r,mid+1,nr,bh*2+1);
    }
    x[bh].mix=x[bh*2].mix+x[bh*2+1].mix;
    x[bh].sum=x[bh*2].sum+x[bh*2+1].sum;
    x[bh].lmax=max(x[bh*2].lmax,x[bh*2].sum+x[bh*2+1].lmax);
    x[bh].rmax=max(x[bh*2+1].rmax,x[bh*2+1].sum+x[bh*2].rmax);
    x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rmax+x[bh*2+1].lmax));
}
int sum(int l,int r,int nl,int nr,int bh)
{
    if(l<nl)
    {
        l=nl;
    }
    if(r>nr)
    {
        r=nr;
    }
    if(l==nl&&r==nr)
    {
        return x[bh].mix;
    }
    if(x[bh].lazy!=0&&nl!=nr)
    {
        pushdown(nl,nr,x[bh].lazy,bh);
    }
    int mid=(nl+nr)/2;
    int ans=0;
    if(l<=mid)
    {
        ans+=sum(l,r,nl,mid,bh*2);
    }
    if(r>=mid+1)
    {
        ans+=sum(l,r,mid+1,nr,bh*2+1);
    }
    return ans; 
}
int add(int l,int r,int nl,int nr,int sl,int bh)
{
    if(l<nl)
    {
        l=nl;
    }
    if(r>nr)
    {
        r=nr;
    }
    if(x[bh].lazy!=0)
    {
        pushdown(nl,nr,x[bh].lazy,bh);
    }
    if(l==nl&&r==nr&&sl>=(r-l+1))
    {
        sl-=x[bh].mix;
        x[bh].mix=0;
        x[bh].lmax=(-100000)*(r-l+1);
        x[bh].rmax=(-100000)*(r-l+1);
        x[bh].maxn=(-100000)*(r-l+1);
        x[bh].sum=(-100000)*(r-l+1);
        x[bh].lazy=-100000;
        return sl;
    }
    int mid=(nl+nr)/2;
    if(l<=mid&&sl!=0)
    {
        sl=add(l,r,nl,mid,sl,bh*2);
    }
    if(r>=mid+1&&sl!=0)
    {
        sl=add(l,r,mid+1,nr,sl,bh*2+1);
    }
    x[bh].mix=x[bh*2].mix+x[bh*2+1].mix;
    x[bh].sum=x[bh*2].sum+x[bh*2+1].sum;
    x[bh].lmax=max(x[bh*2].lmax,x[bh*2].sum+x[bh*2+1].lmax);
    x[bh].rmax=max(x[bh*2+1].rmax,x[bh*2+1].sum+x[bh*2].rmax);
    x[bh].maxn=max(x[bh*2].maxn,max(x[bh*2+1].maxn,x[bh*2].rmax+x[bh*2+1].lmax));
    return sl;
}
tree query(int l,int r,int nl,int nr,int bh)
{
    tree an,bn;
    if(l<nl)
    {
        l=nl;
    }
    if(r>nr)
    {
        r=nr;
    }
    if(x[bh].lazy!=0)
    {
        pushdown(nl,nr,x[bh].lazy,bh);
    }
    if(nl==l&&nr==r)
    {
        an=x[bh];
        return an;
    }
    int ltt=(nl+nr)/2;
    if(l<=ltt&&r<=ltt)
    {
        return an=query(l,r,nl,ltt,bh*2);
    }
    if(r>ltt&&l>ltt)
    {
        return bn=query(l,r,ltt+1,nr,bh*2+1);
    }
    else
    {
        an=query(l,r,nl,ltt,bh*2);
        bn=query(l,r,ltt+1,nr,bh*2+1);
        an.maxn=max(an.maxn,max(bn.maxn,an.rmax+bn.lmax));
        an.lmax=max(an.lmax,an.sum+bn.lmax);
        an.rmax=max(bn.rmax,bn.sum+an.rmax);
        an.sum=an.sum+bn.sum;
        return an;
    }
}
signed main()
{
//  freopen("1.in","r",stdin);
//  freopen("1.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    x[1].lazy=-100000;
    for(rii=1;i<=m;i++)
    {
        int l,r;
        scanf("%lld",&p);
        if(p==0)
        {
            scanf("%lld%lld",&l,&r);
            fg(l,r,1,rs,1);
        }
        if(p==2)
        {
            scanf("%lld%lld",&l,&r);
            tree ans=query(l,r,1,rs,1);
            if(ans.maxn<0)
            {
                ans.maxn=0;
            }
            printf("%lld
",ans.maxn);
        }
        if(p==1)
        {
            int l1,l2,r1,r2;
            scanf("%lld%lld%lld%lld",&l2,&r2,&l1,&r1);
            int ltt=sum(l2,r2,1,rs,1);
            ltt=(r2-l2+1)-ltt;
            fg(l2,r2,1,rs,1);
            if(ltt>(r2-l2+1))
            {
                ltt=r2-l2+1;
            }
            add(l1,r1,1,rs,ltt,1);
        }
    }
}

以上是关于[SHOI2015]脑洞治疗仪(恶心的线段树,区间最大子段和)的主要内容,如果未能解决你的问题,请参考以下文章

[SHOI2015]脑洞治疗仪(线段树?珂朵莉树)

LibreOJ #2037. 「SHOI2015」脑洞治疗仪

[SHOI2015]脑洞治疗仪

[bzoj4592] [Shoi2015]脑洞治疗仪

BZOJ4592[Shoi2015]脑洞治疗仪 线段树

[BZOJ4592][SHOI2015]脑洞治疗仪