动态主席树

本题代码博主还没有认真研究过,但是可以大致脑补出动态主席树的操作。但是还是请你确保你在理解这篇代码之前已经理解了前面的静态主席树和主席树铺垫

友情链接:

主席树铺垫

主席树

然后我们来讲一下动态主席树的思路吧,其实重点只有一句话,但是在这里我还是给大家讲的详细一点。

我们的静态主席树是只支持查询静态区间第k小,那么相信大家已经是非常熟悉他的思路了。但是动态主席树是支持进行在修改的,所以会有一点点不一样,也就是说我们每一次修改一个地方的东西你那么在他之后所有的前缀树都会被得到修改,所以很浪费时间,但是这个问题是可以得到解决的,我们可以用树状数组来实现这一操作······然后我们就套一个树状数组上原来的树就好了。

标程代码如下:

题目链接:
Dynamic Rankings

#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define ls(k) a[k].ch[0]
#define rs(k) a[k].ch[1]
#define low(i) i&(-i)
using namespace std;
struct node { 
    int l,r;int ch[2];int cnt;
};
const int maxn=2e5+10;
int coun=1e9+7,cnt=1;int n,m;
int num[maxn],rot[maxn];
int r1[123],r2[123],cr1,cr2;
node a[maxn*50];
void update(int k) { 
    a[k].cnt=a[ls(k)].cnt+a[rs(k)].cnt;
} 

void ins(int k,int l,int r,int val) { 
    a[k].l=l,a[k].r=r;
    if(l==r) {a[k].cnt++;return;} 
    int mid=l+r;mid/=2;
    if(val<=mid) { 
        if(ls(k)==0) ls(k)=++cnt;
        ins(ls(k),l,mid,val);
    } 
    else { 
        if(rs(k)==0) rs(k)=++cnt;
        ins(rs(k),mid+1,r,val);
    } 
    update(k);
} 

void del(int k,int l,int r,int val) { 
    if(l==r) {a[k].cnt--;return;} 
    int mid=l+r;mid/=2;
    if(val<=mid) del(ls(k),l,mid,val);
    else del(rs(k),mid+1,r,val);
    update(k);
} 

void prit(int k) {
    printf("%d %d %d %d %d %d\n",k,ls(k),rs(k),a[k].l,a[k].r,a[k].cnt);
    if(ls(k)) prit(ls(k));
    if(rs(k)) prit(rs(k));
}

int query(int l,int r,int val) { 
    if(l==r) return r;
    int lsi=0;
    for(int i=1;i<=cr2;++i) lsi+=a[ls(r2[i])].cnt;
    for(int i=1;i<=cr1;++i) lsi-=a[ls(r1[i])].cnt;
    int mid=l+r;mid/=2;
    if(val<=lsi) {
        for(int i=1;i<=cr2;++i) r2[i]=ls(r2[i]);
        for(int i=1;i<=cr1;++i) r1[i]=ls(r1[i]);
        return query(l,mid,val);
    }
    else {
        for(int i=1;i<=cr2;++i) r2[i]=rs(r2[i]);
        for(int i=1;i<=cr1;++i) r1[i]=rs(r1[i]);
        return query(mid+1,r,val-lsi);
    }
} 

int main() { 
    int jcq;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) rot[i]=i; 
    cnt=n+1;
    for(int i=1;i<=n;++i) { 
        scanf("%d",&jcq);
        num[i]=jcq;
        for(int j=i;j<=n;j+=low(j)) { 
            ins(rot[j],0,coun,jcq);
        } 
    } 
    char c;
    int q,w,e;
    for(int i=0;i<m;++i) { 
        cin>>c;
        if(c=='Q') { 
            scanf("%d%d%d",&q,&w,&e);
            cr1=cr2=1;
            for(int i=q-1;i>0;i-=low(i)) r1[cr1]=i,cr1++;
            for(int i=w;i>0;i-=low(i)) r2[cr2]=i,cr2++;
            cr1--;cr2--;
            printf("%d\n",query(0,coun,e));
        } 
        else { 
            scanf("%d%d",&w,&e);
            for(int i=w;i<=n;i+=low(i)) { 
                del(rot[i],0,coun,num[w]);
                ins(rot[i],0,coun,e);
            } 
            num[w]=e;
        } 
    } 
    return 0;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值