BZOJ3065(替罪羊树套线段树)

以前看到这题都瑟瑟发抖,终于过了心情舒畅。

按下标为关键字建替罪羊树,每个结点开一个权值线段树,维护的这个结点代表的子树的信息。

这题还得垃圾回收,自己yy的,不知对不对..

#include <cstdio>
#include <algorithm>
using namespace std;
#define M ((L+R)>>1)
#define l(x) t[x].s[0]
#define r(x) t[x].s[1]
#define L(x) t2[x].s[0]
#define R(x) t2[x].s[1]

const int N=70005;
char op[2];
int n,x,y,z,q,rt,tt,t1,la,tp,tp2,V,st[N],st2[N],rb[N*30],rb2[N*256];
struct nd {int x,v,sz,s[2];}t[N*30],t2[N*256];

void dl(int x) {if(!x) return; rb2[++tt]=x,dl(L(x)),dl(R(x)),t2[x].x=L(x)=R(x)=0;}
void upd(int &o,int L,int R,int x,int y) {
    if(!o) o=rb2[tt--]; t2[o].x+=y;
    if(L==R) return;
    if(x<=M) upd(L(o),L,M,x,y); else upd(R(o),M+1,R,x,y);
    if(!t2[o].x) dl(o),o=0;
}
void ge(int x) {if(!x) return; ge(l(x)),st[++tp]=x,ge(r(x));}
void mr(int l,int r,int &x) {
    if(!l&&!r) return; t2[x=rb2[tt--]].x=t2[l].x+t2[r].x,mr(L(l),L(r),L(x)),mr(R(l),R(r),R(x));
}
void bd(int &x,int L,int R) {
    if(L>R) return; t[x=rb[t1--]].v=t[st[M]].v;
    if(L==R) t[x].sz=1;
    else bd(l(x),L,M-1),bd(r(x),M+1,R),mr(t[l(x)].x,t[r(x)].x,t[x].x),t[x].sz=t[l(x)].sz+t[r(x)].sz+1;
    upd(t[x].x,1,N,t[x].v,1);
}
void rm() {for(int i=1;i<=tp;i++) dl(t[st[i]].x),l(st[i])=r(st[i])=t[st[i]].x=t[st[i]].v=t[st[i]].sz=0;}
void ins(int &x,int p,int v) {
    if(!x) x=rb[t1--]; upd(t[x].x,1,N,v,1),t[x].sz++;
    if(!t[x].v) {t[x].v=v; return;}
    if(t[l(x)].sz+1>=p) ins(l(x),p,v); else ins(r(x),p-t[l(x)].sz-1,v);
    if(t[x].sz*0.75<max(t[l(x)].sz,t[r(x)].sz)) tp=0,ge(x),bd(x,1,tp),rm();
}
void gt(int x,int l,int r) {
    if(r-l+1==t[x].sz) {st[++tp]=t[x].x; return;}
    if(l<=t[l(x)].sz) gt(l(x),l,min(r,t[l(x)].sz));
    if(l<=t[l(x)].sz+1&&r>=t[l(x)].sz+1) st2[++tp2]=t[x].v;
    if(r>t[l(x)].sz+1) gt(r(x),max(l-t[l(x)].sz-1,1),r-t[l(x)].sz-1);
}
int dfs(int L,int R,int k) {
    if(L==R) return L; int s=0;
    for(int i=1;i<=tp;i++) s+=t2[L(st[i])].x;
    for(int i=1;i<=tp2;i++) if(st2[i]<=M&&st2[i]>=L) s++;
    if(s>=k) {
        for(int i=1;i<=tp;i++) st[i]=L(st[i]);
        return dfs(L,M,k);
    } else {
        for(int i=1;i<=tp;i++) st[i]=R(st[i]);
        return dfs(M+1,R,k-s);
    }
}
int qr(int l,int r,int k) {tp=tp2=0,gt(rt,l,r); return dfs(1,N,k);}
void gai(int x,int p,int v) {
    if(t[l(x)].sz+1==p) V=t[x].v,t[x].v=v; else if(t[l(x)].sz>=p) gai(l(x),p,v); else gai(r(x),p-t[l(x)].sz-1,v);
    upd(t[x].x,1,N,v,1),upd(t[x].x,1,N,V,-1);
}

int main() {
    for(int i=1;i<N*30;i++) rb[i]=i;
    for(int i=1;i<N*256;i++) rb2[i]=i;
    scanf("%d",&n),tt=N*256-1,t1=N*30-1;
    for(int i=1;i<=n;i++) scanf("%d",&x),ins(rt,i,x+1);
    scanf("%d",&q);
    while(q--) {
        scanf("%s%d%d",op,&x,&y),x^=la,y^=la;
        if(op[0]=='Q') scanf("%d",&z),printf("%d\n",la=qr(x,y,z^la)-1);
        else if(op[0]=='I') ins(rt,x,y+1);
        else gai(rt,x,y+1);
    }
    return 0;
}

转载于:https://www.cnblogs.com/juruolty/p/6529257.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值