BZOJ4592 [Shoi2015]脑洞治疗仪(洛谷P4344)

292 篇文章 1 订阅
281 篇文章 1 订阅

BZOJ4592: [Shoi2015]脑洞治疗仪(洛谷P4344)

线段树

BZOJ题目传送门
洛谷题目传送门

昨天一个字母打错一晚上没调出来。。。

挺裸的线段树。

0直接做。1记录下 l0 l 0 r0 r 0 的1的个数后可以二分确定修补的右端点,也可以直接往下做到没有为止,前者 log2 log 2 ,后者比 log log 稍微大一点。2对每个节点记一下最左边、最右边、最大的脑洞的长度,查询的时候直接合并就好了,稍微有点细节。

代码:

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
#define F inline
using namespace std;
struct tree{ int mx,s,lx,rx,l,r,f; }t[N<<2];
int n,m,k,s;
F char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    return l==r?EOF:*l++;
}
F int _read(){
    int x=0; char ch=readc();
    while (!isdigit(ch)) ch=readc();
    while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
    return x;
}
F void writec(int x){ if (x>9) writec(x/10); putchar(x%10+48); }
F void _write(int x){ writec(x),puts(""); }
void build(int x,int l,int r){
    t[x].l=l,t[x].r=r,t[x].f=-1;
    if (l==r) return; int mid=l+r>>1;
    build(x<<1,l,mid),build(x<<1|1,mid+1,r);
}
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
F void pshp(int x){
    int l=x<<1,r=x<<1|1; t[x].s=t[l].s+t[r].s;
    t[x].mx=max(max(t[l].mx,t[r].mx),t[l].rx+t[r].lx);
    t[x].lx=t[l].lx,t[x].rx=t[r].rx;
    if (t[l].mx==t[l].r-t[l].l+1) t[x].lx+=t[r].lx;
    if (t[r].mx==t[r].r-t[r].l+1) t[x].rx+=t[l].rx;
}
F void pshd(int x){
    int w=t[x].f,l=x<<1,r=x<<1|1;
    t[x].f=-1,t[l].f=t[r].f=w;
    t[l].lx=t[l].rx=t[l].mx=t[l].s=(w^1)*(t[l].r-t[l].l+1);
    t[r].lx=t[r].rx=t[r].mx=t[r].s=(w^1)*(t[r].r-t[r].l+1);
}
void mdfy(int x,int l,int r){
    if (t[x].l>r||t[x].r<l) return;
    if (t[x].l>=l&&t[x].r<=r){
        t[x].lx=t[x].rx=t[x].mx=t[x].s=t[x].r-t[x].l+1;
        t[x].f=0; return;
    }
    if (~t[x].f) pshd(x);
    mdfy(x<<1,l,r),mdfy(x<<1|1,l,r),pshp(x);
}
tree srch(int x,int l,int r){
    tree xs={0,0,0,0},ls,rs;
    if (t[x].l>r||t[x].r<l) return xs;
    if (t[x].l>=l&&t[x].r<=r) return t[x];
    if (~t[x].f) pshd(x);
    ls=srch(x<<1,l,r),rs=srch(x<<1|1,l,r);
    xs.mx=max(max(ls.mx,rs.mx),ls.rx+rs.lx);
    xs.lx=ls.lx,xs.rx=rs.rx;
    if (ls.lx==min(r,t[x<<1].r)-max(l,t[x<<1].l)+1)
        xs.lx+=rs.lx;
    if (rs.rx==min(r,t[x<<1|1].r)-max(l,t[x<<1|1].l)+1)
        xs.rx+=ls.rx;
    xs.s=ls.s+rs.s; return xs;
}
void chng(int x,int l,int r){
    if (t[x].l>r||t[x].r<l||s==0) return;
    if (t[x].l>=l&&t[x].r<=r)
        if (s>=t[x].s){
            s-=t[x].s,t[x].f=1;
            t[x].lx=t[x].rx=t[x].mx=t[x].s=0; return;
        }
    if (~t[x].f) pshd(x);
    chng(x<<1,l,r),chng(x<<1|1,l,r),pshp(x);
}
int main(){
    for (n=_read(),m=_read(),build(1,1,n);m;m--){
        int f=_read(),l=_read(),r=_read(),L,R;
        if (f==0) mdfy(1,l,r);
        else if (f==1){
            L=_read(),R=_read(),s=r-l+1-srch(1,l,r).s;
            mdfy(1,l,r),chng(1,L,R);
        }
        else _write(srch(1,l,r).mx);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值