BZOJ3065: 带插入区间K小值(替罪羊树+权值线段树)

来源:互联网 发布:单簧管 笛头 知乎 编辑:程序博客网 时间:2024/05/19 09:15

传送门

题意:
带插入区间K小值

题解:
替罪羊树+权值线段树,替罪羊的每一个节点维护子树的权值线段树,暴力重建即可。
每次插入复杂度O(log2n),查询O(log2n)

#include<bits/stdc++.h>using namespace std;struct IO{    streambuf *ib,*ob;    inline void init(){        ios::sync_with_stdio(false);        cin.tie(NULL),cout.tie(NULL);        ib=cin.rdbuf();ob=cout.rdbuf();    }    inline int read(){        char ch=ib->sbumpc();int i=0,f=1;        while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}        while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();}        return i*f;    }    inline void W(int x){        static int buf[50];        if(!x){ob->sputc('0');ob->sputc('\n');return;}        if(x<0){ob->sputc('-');x=-x;}        while(x){buf[++buf[0]]=x%10;x/=10;}        while(buf[0])        {ob->sputc(buf[buf[0]--]+'0');}        ob->sputc('\n');    }}io;const int Maxn=2e5+50;int n,lastans;struct node2{    node2 *lc,*rc;    int sze;    inline void upt(){        sze=lc->sze+rc->sze;    }}Pool2[Maxn<<5],*pool2=Pool2,*null2=Pool2;node2* recyclepool2[Maxn<<5];int tail2=0;inline node2* newnode2(){    node2* tmp=(tail2)?(recyclepool2[tail2--]):(++pool2);    tmp->lc=tmp->rc=null2;    tmp->sze=0;    return tmp;}inline void insert2(node2*& now,int l,int r,int val,int bz=1){    if(l==r){if(now==null2)now=newnode2();now->sze+=bz;return;}    if(now==null2)now=newnode2();    int mid=(l+r)>>1;    if(val<=mid)insert2(now->lc,l,mid,val,bz);    else insert2(now->rc,mid+1,r,val,bz);    now->upt();}struct node1{    node1 *lc,*rc;    node2 *rt;    int val,sze,exi;    inline void upt(){        sze=lc->sze+rc->sze+exi;    }}Pool1[Maxn],*pool1=Pool1,*null1=Pool1;node1* recyclepool1[Maxn];int tail1=0;inline node1* newnode1(int val){    node1* tmp=((tail1)?(recyclepool1[tail1--]):(++pool1));    tmp->lc=tmp->rc=null1;    tmp->sze=tmp->exi=1;tmp->val=val;    tmp->rt=null2;    return tmp;}inline void recyclenode2(node2*& now){    if(now==null2)return;    recyclepool2[++tail2]=now;    if(now->lc!=null2)recyclenode2(now->lc);    if(now->rc!=null2)recyclenode2(now->rc);    now=null2;}int a[Maxn],tot;inline void recyclenode1(node1*& now,int *a){    if(now==null1)return;    recyclenode2(now->rt);    recyclepool1[++tail1]=now;    if(now->lc!=null1)recyclenode1(now->lc,a);    if(now->exi)a[++tot]=now->val;    if(now->rc!=null1)recyclenode1(now->rc,a);    now=null1;}inline int query2(node2* now,int l,int r,int val){    if(val<l||val>r||now==null2)return 0;    if(r<=val)return now->sze;    int mid=(l+r)>>1;    if(val<=mid)return query2(now->lc,l,mid,val);    else return now->lc->sze+query2(now->rc,mid+1,r,val);}const int alpha=70;struct ScapeGoatTree{    node1* rt;    node2* que[Maxn];    int t[Maxn],tmp,tail;    ScapeGoatTree():rt(null1){}    inline void build(node1*& now,int *a,int l,int r){        int mid=(l+r)>>1;        now=newnode1(a[mid]);        for(int i=l;i<=r;i++)insert2(now->rt,0,Maxn-1,a[i]);        if(l==r)return;        if(l<mid)build(now->lc,a,l,mid-1);        if(mid<r)build(now->rc,a,mid+1,r);        now->upt();    }    inline void insert_val(node1 *&now,int pos,int val,node1**&p){        if(now==null1){            now=newnode1(val);            insert2(now->rt,0,Maxn-1,val);            return;        }        insert2(now->rt,0,Maxn-1,val);        if(now->lc->sze+now->exi<=pos)insert_val(now->rc,pos-now->lc->sze-now->exi,val,p);        else insert_val(now->lc,pos,val,p);        now->upt();        if(now->sze*alpha<now->lc->sze*100||now->sze*alpha<now->rc->sze*100)p=&now;    }    inline void rebuild(node1 *&now){        tot=0;        recyclenode1(now,a);        build(now,a,1,tot);    }    inline void insert(int pos,int val){        node1 **p=&null1;        insert_val(rt,pos,val,p);        if(*p!=null1)rebuild(*p);    }    inline void erase_val(node1*& now,int pos,int val,node1**& p){        insert2(now->rt,0,Maxn-1,val,-1);        if(now->lc->sze>=pos)erase_val(now->lc,pos,val,p);        else if(now->lc->sze+now->exi==pos)now->exi=0;        else erase_val(now->rc,pos-now->lc->sze-now->exi,val,p);        now->upt();        if(now->sze*alpha<now->lc->sze*100||now->sze*alpha<now->rc->sze*100)p=&now;    }    inline void del(int pos,int val){        node1 **p=&null1;        erase_val(rt,pos,val,p);        if(*p!=null1)rebuild(*p);    }    inline int findkth(int pos){        node1 *tmp=rt;        while(tmp!=null1){            if(tmp->lc->sze>=pos)tmp=tmp->lc;            else if(tmp->lc->sze+tmp->exi==pos)return tmp->val;            else pos-=(tmp->lc->sze+tmp->exi),tmp=tmp->rc;        }    }    inline void find(node1 *now,int l,int r,int L,int R){        if(L<=l&&r<=R){if(now->rt!=null2)que[++tail]=now->rt;return;}        if(now->lc!=null1&&l+now->lc->sze-1>=L&&(R>=l))find(now->lc,l,l+now->lc->sze-1,L,R);        if(now->rc!=null1&&l+now->lc->sze+now->exi<=R&&(r>=L))find(now->rc,l+now->lc->sze+now->exi,r,L,R);        if(L<=l+now->lc->sze+now->exi-1&&l+now->lc->sze+now->exi-1<=R&&now->exi)t[++tmp]=now->val;        return;    }    inline int query(int l,int r,int k){        tmp=tail=0;        find(rt,1,rt->sze,l,r);        int lval=0,rval=Maxn-1,ans=0;        while(lval<=rval){            int mid=(lval+rval)>>1,cnt=0;             for(int i=1;i<=tail;i++)            cnt+=query2(que[i],0,Maxn-1,mid);            for(int i=1;i<=tmp;i++)if(t[i]<=mid)cnt++;            if(cnt>=k)ans=mid,rval=mid-1;            else lval=mid+1;        }        return ans;    }}SGT;int main(){    io.init();    n=io.read();    for(int i=1;i<=n;i++)a[i]=io.read();    SGT.build(SGT.rt,a,1,n);    int m=io.read();    while(m--){        static char op[2];        cin>>(op+1);        if(op[1]=='Q'){            int l=io.read()^lastans,r=io.read()^lastans,k=io.read()^lastans;            lastans=SGT.query(l,r,k);            io.W(lastans);         }        else if(op[1]=='M'){            int pos=io.read()^lastans,val=io.read()^lastans;            SGT.del(pos,SGT.findkth(pos));            SGT.insert(pos-1,val);        }        else{            int pos=io.read()^lastans,val=io.read()^lastans;            SGT.insert(pos-1,val);        }    }}
原创粉丝点击