可持久化平衡树

可持久化普通平衡树

题意

如题。

解法

大家都知道,用权值线段树可以过普通平衡树那道题,那么对于可持久化普通平衡树,我们是否也可以用主席树来搞一搞呢。答案是肯定的。只需要动态开点就行了。其他的跟普通平衡树那道题一模一样。

代码

这里需要注意一点,当 l 和 r 都是负数的时候, /2 就会有问题,因为 $ -5/2 = -2$ 而 $ -5 >> 1 = -3$ ,所以除2会使 l 一直小于mid,从而陷入死循环。

#include <bits/stdc++.h>
#define INF 2147483647
using namespace std;
template <typename T>
inline void read(T &x) {
    x=0;T k=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') k=-1;c=getchar();}
    while(isdigit(c)) {x=x*10+c-'0';c=getchar();}x*=k;
}

const int maxn=5e5+5;
const int ll=-1e9,rr=1e9;
struct node {
    int lc,rc,sum;
}T[maxn*40];

int root[maxn],sz;

void update(int l,int r,int pos,int val,int &x,int y) {
    T[++sz]=T[y],x=sz;
    if(l==r) {
        if(!(T[x].sum==0&&val<0)) T[x].sum+=val;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid) update(l,mid,pos,val,T[x].lc,T[y].lc);
    else update(mid+1,r,pos,val,T[x].rc,T[y].rc);
    T[x].sum=T[T[x].lc].sum+T[T[x].rc].sum;
}

int query(int l,int r,int pos,int x) {
    if(l==r) return 0;
    int mid=(l+r)>>1;
    if(pos<=mid) return query(l,mid,pos,T[x].lc);
    return T[T[x].lc].sum+query(mid+1,r,pos,T[x].rc);
}

int kth(int l,int r,int k,int x) {
    if(l==r) return l;
    int mid=(l+r)>>1,sum=T[T[x].lc].sum;
    if(k<=sum) return kth(l,mid,k,T[x].lc);
    else return kth(mid+1,r,k-sum,T[x].rc);
}

int pre(int l,int r,int pos,int x) {
    int k=query(l,r,pos,x);
    if(k==0) return -INF;
    else return kth(l,r,k,x);
}

int query_muilt(int l,int r,int pos,int x) {
    if(l==r) return T[x].sum;
    int mid=(l+r)>>1;
    if(pos<=mid) return query_muilt(l,mid,pos,T[x].lc);
    else return query_muilt(mid+1,r,pos,T[x].rc);
}

int nxt(int l,int r,int pos,int x) {
    int a1=query(l,r,pos,x),a2=query_muilt(l,r,pos,x);
    if(a1+a2==T[x].sum) return INF;
    return kth(l,r,a1+a2+1,x);
}

int n;
int main() {
    read(n);
    for(int i=1;i<=n;i++) {
        int v,opt,x;
        read(v),read(opt),read(x);
        switch(opt) {
            case 1 : {update(ll,rr,x,1,root[i],root[v]);break;} 
            case 2 : {update(ll,rr,x,-1,root[i],root[v]);break;} 
            case 3 : {root[i]=root[v],printf("%d\n",query(ll,rr,x,root[i])+1);break;} 
            case 4 : {root[i]=root[v],printf("%d\n",kth(ll,rr,x,root[i]));break;} 
            case 5 : {root[i]=root[v],printf("%d\n",pre(ll,rr,x,root[i]));break;} 
            case 6 : {root[i]=root[v],printf("%d\n",nxt(ll,rr,x,root[i]));break;} 
        }
    }
    return 0;
}
/*
10
0 1 9
1 1 3
1 1 10
2 4 2
3 3 9
3 1 2
6 4 1
6 2 9
8 6 3
4 5 8

*/

转载于:https://www.cnblogs.com/mrasd/p/9532263.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值