BZOJ4592 SHOI2015脑洞治疗仪(线段树)

  考虑需要资瓷哪些操作:区间赋值为0;统计区间1的个数;将区间前k个0变为1;询问区间最长全0子串。于是线段树维护区间1的个数、0的个数、最长前缀后缀全0子串即可。稍微困难的是用一个log实现将区间前k个0变为1,线段树上二分尽量往左边改即可,可以令修改函数返回值为剩余能改的1的个数。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int n,m,L[N<<2],R[N<<2];
struct data{int sum0,sum1,pre,suf,len,lazy;
}tree[N<<2];
void update(int k,int x)
{
    if (x==0)
    {
        tree[k].sum0=tree[k].pre=tree[k].suf=tree[k].len=R[k]-L[k]+1;
        tree[k].sum1=0;
    }
    else
    {
        tree[k].sum0=tree[k].pre=tree[k].suf=tree[k].len=0;
        tree[k].sum1=R[k]-L[k]+1;
    }
    tree[k].lazy=x;
}
void up(int k) 
{
    tree[k].sum0=tree[k<<1].sum0+tree[k<<1|1].sum0;
    tree[k].sum1=tree[k<<1].sum1+tree[k<<1|1].sum1;
    if (tree[k<<1].pre==R[k<<1]-L[k<<1]+1) tree[k].pre=tree[k<<1].pre+tree[k<<1|1].pre;
    else tree[k].pre=tree[k<<1].pre;
    if (tree[k<<1|1].suf==R[k<<1|1]-L[k<<1|1]+1) tree[k].suf=tree[k<<1|1].suf+tree[k<<1].suf;
    else tree[k].suf=tree[k<<1|1].suf;
    tree[k].len=max(max(tree[k<<1].len,tree[k<<1|1].len),tree[k<<1].suf+tree[k<<1|1].pre);
}
void down(int k)
{
    update(k<<1,tree[k].lazy);
    update(k<<1|1,tree[k].lazy);
    tree[k].lazy=-1;
}
void build(int k,int l,int r)
{
    L[k]=l,R[k]=r;tree[k].lazy=-1;
    if (l==r) {tree[k].sum1=1;return;}
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    up(k);
}
void modify(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) {update(k,0);return;}
    if (~tree[k].lazy) down(k);
    int mid=L[k]+R[k]>>1;
    if (r<=mid) modify(k<<1,l,r);
    else if (l>mid) modify(k<<1|1,l,r);
    else modify(k<<1,l,mid),modify(k<<1|1,mid+1,r);
    up(k);
}
int calc(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) return tree[k].sum1;
    if (~tree[k].lazy) down(k);
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return calc(k<<1,l,r);
    else if (l>mid) return calc(k<<1|1,l,r);
    else return calc(k<<1,l,mid)+calc(k<<1|1,mid+1,r);
}
int query(int k,int l,int r)
{
    if (L[k]==l&&R[k]==r) return tree[k].len;
    if (~tree[k].lazy) down(k);
    int mid=L[k]+R[k]>>1;
    if (r<=mid) return query(k<<1,l,r);
    else if (l>mid) return query(k<<1|1,l,r);
    else return max(max(query(k<<1,l,mid),query(k<<1|1,mid+1,r)),min(tree[k<<1].suf,mid-l+1)+min(tree[k<<1|1].pre,r-mid));
}
int paint(int k,int l,int r,int x)
{
    if (!x) return 0;
    if (L[k]==l&&R[k]==r&&x>=tree[k].sum0) {x-=tree[k].sum0;update(k,1);return x;}
    if (~tree[k].lazy) down(k);
    int mid=L[k]+R[k]>>1;
    if (r<=mid) x=paint(k<<1,l,r,x);
    else if (l>mid) x=paint(k<<1|1,l,r,x);
    else
    {
        int t=paint(k<<1,l,mid,x);
        if (t>=0) x=paint(k<<1|1,mid+1,r,t);
        else x=0;
    }
    up(k);
    return x;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4592.in","r",stdin);
    freopen("bzoj4592.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();
    build(1,1,n);
    while (m--)
    {
        int op=read(),l=read(),r=read();
        if (op==0) modify(1,l,r);
        else if (op==1)
        {
            int x=read(),y=read();
            int k=calc(1,l,r);
            modify(1,l,r);
            paint(1,x,y,k);
        }
        else printf("%d\n",query(1,l,r));
    }
    return 0;
}

 

posted @ 2018-11-03 11:47  Gloid  阅读(216)  评论(0编辑  收藏  举报