BZOJ 4592 脑洞治疗仪

天啦噜我自己YY的从任意起点开始的线段树上二分居然是对的。。。。

好感动啊。

4.7k的代码只调了一个晚上好感动。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200500
using namespace std;
int n,m,sum[maxn<<2],lazy[maxn<<2],ls[maxn<<2],rs[maxn<<2],tot=0,root,l[maxn<<2],r[maxn<<2],mx[maxn<<2];
int type,l1,r1,l2,r2;
struct status
{
    int mx,l,r,len;
    status (int mx,int l,int r,int len):mx(mx),l(l),r(r),len(len) {}
    status () {}
};
void build(int &now,int left,int right)
{
    now=++tot;sum[now]=right-left+1;lazy[now]=-1;
    if (left==right) return;
    int mid=(left+right)>>1;
    build(ls[now],left,mid);
    build(rs[now],mid+1,right);
}
void pushdown(int now,int left,int right)
{
    if (lazy[now]==-1) return;
    lazy[ls[now]]=lazy[rs[now]]=lazy[now];
    int mid=(left+right)>>1,ll=mid-left+1,rl=right-mid;
    sum[ls[now]]=lazy[ls[now]]*ll;sum[rs[now]]=lazy[rs[now]]*rl;
    l[ls[now]]=r[ls[now]]=mx[ls[now]]=(lazy[now]^1)*ll;
    l[rs[now]]=r[rs[now]]=mx[rs[now]]=(lazy[now]^1)*rl;
    lazy[now]=-1;
}
void pushup(int now,int left,int right)
{
    sum[now]=sum[ls[now]]+sum[rs[now]];
    int mid=(left+right)>>1,ll=mid-left+1,rl=right-mid;
    if (mx[ls[now]]==ll) l[now]=ll+l[rs[now]];else l[now]=l[ls[now]];
    if (mx[rs[now]]==rl) r[now]=rl+r[ls[now]];else r[now]=r[rs[now]];
    mx[now]=max(r[ls[now]]+l[rs[now]],max(mx[ls[now]],mx[rs[now]]));
}
void modify1(int now,int left,int right,int lq,int rq,int val)
{
    pushdown(now,left,right);
    if (left==lq && right==rq)
    {
        lazy[now]=val;sum[now]=lazy[now]*(right-left+1);
        l[now]=r[now]=mx[now]=(right-left+1)*(val^1);
        return;
    }
    int mid=(left+right)>>1;
    if (rq<=mid) modify1(ls[now],left,mid,lq,rq,val);
    else if (lq>=mid+1) modify1(rs[now],mid+1,right,lq,rq,val);
    else modify1(ls[now],left,mid,lq,mid,val),modify1(rs[now],mid+1,right,mid+1,rq,val);
    pushup(now,left,right);
}
int warn=0;
int modify3(int now,int left,int right,int k)
{
    warn++;
    pushdown(now,left,right);
    int kk=right-left+1-sum[now];
    if (k>=kk)
    {
        sum[now]=right-left+1;lazy[now]=1;
        mx[now]=l[now]=r[now]=0;
        return kk;
    }
    if (left==right)
    {
        sum[now]=1;mx[now]=l[now]=r[now]=0;
        return 1;
    }
    int mid=(left+right)>>1,rr=mid-left+1-sum[ls[now]],ret=0;
    if (k<=rr) ret=modify3(ls[now],left,mid,k);
    else
    {
        sum[ls[now]]=mid-left+1;lazy[ls[now]]=1;
        mx[ls[now]]=l[ls[now]]=r[ls[now]]=0;
        ret=rr+modify3(rs[now],mid+1,right,k-rr);
    }
    pushup(now,left,right);return ret;
}
int modify2(int now,int left,int right,int l,int r,int k)
{
    warn++;
    pushdown(now,left,right);
    if ((left==l) && (right==r)) return modify3(now,left,right,k);
    int mid=(left+right)>>1,ret=0;
    if (r<=mid)
    {
        if (mid-left+1-sum[ls[now]]>0)
            ret=modify2(ls[now],left,mid,l,r,k);
    }
    else if (l>=mid+1)
    {
        if (right-mid-sum[rs[now]]>0)
            ret=modify2(rs[now],mid+1,right,l,r,k);
    }
    else
    {
        if (mid-left+1-sum[ls[now]]) ret=modify2(ls[now],left,mid,l,mid,k);
        if ((k>ret) && (right-mid-sum[rs[now]])) ret+=modify2(rs[now],mid+1,right,mid+1,r,k-ret);
    }
    pushup(now,left,right);return ret;
}
status merge(status x,status y)
{
    status ret=status(0,0,0,0);
    if (x.mx==x.len) ret.l=x.len+y.l;else ret.l=x.l;
    if (y.mx==y.len) ret.r=y.len+x.r;else ret.r=y.r;
    ret.mx=max(x.r+y.l,max(x.mx,y.mx));
    ret.len=x.len+y.len;
    return ret;
}
int ask1(int now,int left,int right,int l,int r)
{
    pushdown(now,left,right);
    if (left==l && right==r) return sum[now];
    int mid=(left+right)>>1;
    if (r<=mid) return ask1(ls[now],left,mid,l,r);
    else if (l>=mid+1) return ask1(rs[now],mid+1,right,l,r);
    else return ask1(ls[now],left,mid,l,mid)+ask1(rs[now],mid+1,right,mid+1,r);
}
status ask2(int now,int left,int right,int lq,int rq)
{
    pushdown(now,left,right);
    if ((left==lq) && (right==rq)) return status(mx[now],l[now],r[now],right-left+1);
    int mid=(left+right)>>1;
    if (rq<=mid) return ask2(ls[now],left,mid,lq,rq);
    else if (lq>=mid+1) return ask2(rs[now],mid+1,right,lq,rq);
    else return merge(ask2(ls[now],left,mid,lq,mid),ask2(rs[now],mid+1,right,mid+1,rq));
}
int main()
{
    scanf("%d%d",&n,&m);
    build(root,1,n);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&type,&l1,&r1);
        if (!type) modify1(root,1,n,l1,r1,0);
        else if (type==1)
        {
            warn=0;
            scanf("%d%d",&l2,&r2);
            int ret=ask1(root,1,n,l1,r1);
            modify1(root,1,n,l1,r1,0);
            if (ret) {int kr=modify2(root,1,n,l2,r2,ret);kr++;}
        }
        else printf("%d\n",ask2(root,1,n,l1,r1).mx);
    }
    return 0;
}
时间: 2024-10-24 15:38:27

BZOJ 4592 脑洞治疗仪的相关文章

【BZOJ-4592】脑洞治疗仪 线段树

4592: [Shoi2015]脑洞治疗仪 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 69  Solved: 38[Submit][Status][Discuss] Description 曾经发明了自动刷题机的发明家SHTSC又公开了他的新发明:脑洞治疗仪--一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见,我们将大脑视作一个01序列.1代表这个位置的脑组织正常工作,0代表这是一块脑洞. 1 0 1 0 0 0 1 1 1

bzoj4592 [Shoi2015]脑洞治疗仪

Description 曾经发明了自动刷题机的发明家SHTSC又公开了他的新发明:脑洞治疗仪--一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见,我们将大脑视作一个01序列.1代表这个位置的脑组织正常工作,0代表这是一块脑洞. 1 0 1 0 0 0 1 1 1 0 脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中. (所以脑洞治疗仪是脑洞的治疗仪?) 例如,用上面第8号位置到第10号位置去修补第1号位置到第4号位置的脑洞.我

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

#2037. 「SHOI2015」脑洞治疗仪 题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见,我们将大脑视作一个 01 序列.1 代表这个位置的脑组织正常工作,0 代表这是一块脑洞. 1 0 1 0 0 0 1 1 1 0 脑洞治疗仪修补某一块脑洞的基本工作原理就是将另一块连续区域挖出,将其中正常工作的脑组织填补在这块脑洞中.(所以脑洞治疗仪是脑洞的治疗仪?) 例如,用上面第 8 号位置到第 

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

线段树区间合并问题 恶心... 屠龙宝刀点击就送 #include <cstdio> #define N 200005 struct Segment { int l,r,mid,sum,lm,rm,m,len,flag; Segment * ch[2]; Segment () { ch[0]=ch[1]=NULL; lm=rm=m=0; flag=-1; } }*root=new Segment; int n,m,tmp,ans,nowl; inline int max(int a,int b

SHOI2015 脑洞治疗仪

给你一个序列,一开始都是 $1$,资瓷 $3$ 种操作 1.把 $[l,r]$ 赋值为 $0$ 2.把 $[l,r]$ 中所有 $1$ 删掉,记录删掉的 $1$ 的个数,并把这些 $1$ 从左到右填到 $[a,b]$ 中的 $0$ 处,不考虑 $1$ 的剩余(剩下的相当于全扔了) 3.查询 $[l,r]$ 中最长连续的 $0$ 的个数 sol: 好像会珂朵莉树这题就是模拟啊...应该是当年 SHOI 的人不知道有这种黑珂技 感觉跑的比线段树快呀... #include<bits/stdc++.h

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

题面 这道题超级可爱呢,珂朵莉最可爱了,不,小哀才是最可爱的呢 很好的题,可以考虑用线段树维护,hale表示线段树思路很难,而且难打,不如滚去写珂朵莉树哦 对于操作一:直接将set修改插入即可 对于操作三:最大连续子段和(线段树里面是这样叫的吧)维护即可 对于操作二:我们发现可以考虑先将这段区间里面的1 全部取出来,然后暴力合并区间为0,插入会set里面 之后枚举要修改的区间,从左端点开始搞起,一直后搜索,最后加一个判断,是否已经完全ok即可,具体可参见代码 好了,这道题就解决了 我的代码好像l

Bzoj 4591: [Shoi2015]超能粒子炮&#183;改 数论,Lucas定理,排列组合

4591: [Shoi2015]超能粒子炮·改 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 178  Solved: 70[Submit][Status][Discuss] Description 曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加 强大的粒子流的神秘装置.超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升.它有三个参数n,k.它会 向编号为0到k的位置发射威力为C(n

【bzoj4591】 [Shoi2015]超能粒子炮&#183;改

Description 曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加 强大的粒子流的神秘装置.超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升.它有三个参数n,k.它会 向编号为0到k的位置发射威力为C(n,k) mod 2333的粒子流.现在SHTSC给出了他的超能粒子炮·改的参数,让你求 其发射的粒子流的威力之和模2333. Input 第一行一个整数t.表示数据组数. 之后t行,每行二个整数n,k.含义如题面描述. k<

【bzoj4591】[Shoi2015]超能粒子炮&#183;改 Lucas定理

题目描述 曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加强大的粒子流的神秘装置.超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升.它有三个参数n,k.它会向编号为0到k的位置发射威力为C(n,k) mod 2333的粒子流.现在SHTSC给出了他的超能粒子炮·改的参数,让你求其发射的粒子流的威力之和模2333. 输入 第一行一个整数t.表示数据组数. 之后t行,每行二个整数n,k.含义如题面描述. k<=n<=10^18