码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj4697: 猪

时间:2017-07-07 00:50:05      阅读:240      评论:0      收藏:0      [点我收藏+]

标签:需要   [1]   printf   改变   空间   inpu   pre   否则   struct   

Description

红学姐和黄学长是好朋友。红学姐有一只宠物,叫魔法猪。黄学长也有一只宠物,叫小奇。有 n 个猪圈排成一排
,魔法猪藏在某个猪圈中。为了找到魔法猪,小奇会向你询问一些猪圈中猪的个数和。在询问的过程中,魔法猪可
能会释放魔法来改变这些猪圈。
共有 m 次操作。每次操作是以下三种之一。
Q x y 询问从左到右第 x 个猪圈到第 y 个猪圈中猪的个数和。
C x y 将从左到右第 x 个猪圈中猪的个数变为 y。
M x y 将从左到右第 x 个猪圈移动到第 y 个猪圈的位置,并将第 y 个猪圈到第 x-1 个猪圈全部右移一格。保证
 x>y。保证任何时候每个猪圈中猪的数量在 0 至 1000000 之间。

Input

第一行包含两个整数 n,m,其值均小于等于10^5
第二行 n 个整数表示从左到右每个猪圈中猪的个数。
接下来 m 行每行一个操作。

Output

对于每个询问操作,输出一行一个整数表示答案。
由于卡空间,这里考虑平衡树套分块以减小空间常数,若取块大小为B=O(logn)则不会增加时间复杂度
限制块大小为[B,2B-1],但最后一块为[1,2B-1],在插入删除时可能破坏这一性质,需要相应维护
插入:
  若插入后块大小为2B,则将这个块分裂。
删除:
  对最后一个块,若删除后块大小为0,则删去这一块。
  对其余的块,若删除后块大小为B-1,则考虑下一个块:
    若下一个块大小为B,则合并这两个块,
    否则将下一个块的第一个元素移到当前块的末尾。
#include<cstdio>
#include<cstdlib>
const int B=10,B2=B*2,M=32768,N=100111;
typedef long long i64;
i64 _a;
#define lc c[0]
#define rc c[1]
struct node{
    int v[B2];
    node*c[2];
    i64 s2;
    int sz,len,rnd,s1;
    void init(int D){
        lc=rc=0;
        sz=len=D;
        rnd=rand();
        s2=s1;
    }
    void read(int D){
        init(D);
        s1=0;
        for(int i=0;i<len;++i)scanf("%d",v+i),s1+=v[i];
        s2=s1;
    }
    void get(node*a){
        init(B);
        s1=0;
        for(int i=0,*b=a->v+B;i<B;++i)s1+=v[i]=b[i];
        a->s1-=s1,a->len=B;
        s2=s1;
    }
    void up(){
        sz=len,s2=s1;
        if(lc)sz+=lc->sz,s2+=lc->s2;
        if(rc)sz+=rc->sz,s2+=rc->s2;
    }
    void sum(int L,int R){
        if(!this)return;
        if(L<=1&&R>=sz){
            _a+=s2;
            return;
        }
        int ls=lc?lc->sz:0;
        if(L<=ls)lc->sum(L,R),L=ls+1;
        L-=ls,R-=ls;
        if(R>len)rc->sum(L-len,R-len),R=len;
        if(L==1&&R==len)_a+=s1;
        else for(--L;L<R;++L)_a+=v[L];
    }
    void set(int w,int x){
        int ls=lc?lc->sz:0;
        if(w<=ls)lc->set(w,x);
        else if(w>ls+len)rc->set(w-ls-len,x);
        else{
            w-=ls+1;
            s1+=x-v[w];
            v[w]=x;
        }
        up();
    }
    node*chk(int d){
        if(c[d]&&c[d]->rnd>rnd){
            node*u=c[d];
            c[d]=u->c[d^1];
            u->c[d^1]=this;
            return up(),u->up(),u;
        }
        return up(),this;
    }
    node*del(int x);
    node*ins(int x);
}ns[N/B+5],*ss[N/B+5],*rt,*tmp;
int n,m,sp=0,flag,_pos;
node*mg(node*a,node*b){
    if(!a)return b;
    if(!b)return a;
    if(a->rnd>b->rnd){
        a->rc=mg(a->rc,b);
        a->up();
        return a;
    }else{
        b->lc=mg(a,b->lc);
        b->up();
        return b;
    }
}
node*node::del(int w){
    int ls=lc?lc->sz:0;
    if(w<=ls)return lc=lc->del(w),chk(0);
    if(w>ls+len)return rc=rc->del(w-ls-len),chk(1);
    if(flag&&len<=B){
        flag=0;
        for(int i=len-1;i>=0;--i)v[i+B-1]=v[i];
        for(int i=0;i<B-1;++i)v[i]=tmp->v[i];
        len+=B-1,sz+=B-1;
        s1+=tmp->s1,s2+=tmp->s1;
        ss[sp++]=tmp;
        return this;
    }
    _a=v[w-ls-1];
    s1-=_a,s2-=_a;
    for(int i=w-ls;i<len;++i)v[i-1]=v[i];
    --len,--sz;
    if(flag){
        tmp->s1+=tmp->v[B-1]=_a;
        tmp->init(B);
        return lc=mg(lc,tmp),chk(0);
    }
    if(len<B){
        if(!len)ss[sp++]=this;
        else flag=1,_pos=ls-w,tmp=this;
        return mg(lc,rc);
    }
    return this;
}
node*node::ins(int w){
    int ls=lc?lc->sz:0;
    if(w<=ls)return lc=lc->ins(w),chk(0);
    if(w>ls+len+1)return rc=rc->ins(w-ls-len),chk(1);
    w-=ls+1;
    for(int i=len++;i>w;--i)v[i]=v[i-1];
    v[w]=_a;
    s1+=_a,s2+=_a;
    if(len<B2)return up(),this;
    tmp=ss[--sp];
    tmp->get(this);
    return rc=mg(tmp,rc),chk(1);
}
int main(){
    scanf("%d%d",&n,&m);
    srand(n^m<<1^1512);
    for(int i=0,mx=n/B+1;i<mx;++i)ss[sp++]=ns+i;
    for(int D=B*3/2,l=1,r=D;l<=n;l+=D,r+=D){
        if(r>n)r=n;
        node*w=ss[--sp];
        w->read(r-l+1);
        rt=mg(rt,w);
    }
    for(;m;--m){
        char o;
        int a,b;
        scanf(" %c %d%d",&o,&a,&b);
        if(o==Q-48){
            _a=0;
            rt->sum(a,b);
            printf("%lld\n",_a);
        }else if(o==C-48){
            rt->set(a,b);
        }else{
            flag=0;
            rt=rt->del(a);
            if(flag){
                _pos+=a+1;
                if(_pos<=n-1-tmp->len){
                    i64 a0=_a;
                    rt=rt->del(_pos);
                    _a=a0;
                }else{
                    tmp->init(tmp->len);
                    rt=mg(rt,tmp);
                }
            }
            rt=rt->ins(b);
        }
    }
    return 0;
}

 

bzoj4697: 猪

标签:需要   [1]   printf   改变   空间   inpu   pre   否则   struct   

原文地址:http://www.cnblogs.com/ccz181078/p/7129101.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!