带修改的主席树

Posted Candy?

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了带修改的主席树相关的知识,希望对你有一定的参考价值。

普通主席树认为是前缀套线段树,那么这就是树状数组套线段树

前缀区间由原来的一个前缀一个线段树变成BIT组成的几棵线段树一起

每个线段树维护的还是离散排序后的数列

每个节点也相当于一个主席树,我觉得更像是线段树,但是修改的时候用到了主席树的方法,就是在原来的基础上修改(只不过这些原来的都不保存)

add操作要修改一些主席树

sum操作要加一些主席树的区间和

外层的BIT是为了处理询问区间,内层是为了找k值

kth时候要把用到的主席树提出了,每个都往左往右

 

代码(未提交过)

//
//  main.cpp
//  zoj2112
//
//  Created by Candy on 2016/12/11.
//  Copyright © 2016年 Candy. All rights reserved.
//

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=6e4+5;
inline int read(){
    char c=getchar();int x=0,f=1;
    while(c<0||c>9){if(c==-)f=-1; c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0; c=getchar();}
    return x*f;
}
int n,Q,m,a[N],mp[N],i,j,k;
char s[2];
struct question{
    char s[2];
    int i,j,k,x,d;
}q[N];
inline int Bin(int v){
    int l=1,r=m;
    while(l<=r){
        int mid=(l+r)>>1;
        if(mp[mid]==v) return mid;
        if(mp[mid]>v) r=mid-1;
        else l=mid+1;
    }
    return -1;
}

inline int lowbit(int x){return x&-x;}
int c[N];
struct node{
    int lc,rc,w;
}t[N*20];
int cnt=0,root[N];
void ins(int &x,int l,int r,int num,int v){//1 -1
    t[++cnt]=t[x];x=cnt;
    t[x].w+=v;
    if(l==r) return;
    int mid=(l+r)>>1;
    if(num<=mid) ins(t[x].lc,l,mid,num,v);
    else ins(t[x].rc,mid+1,r,num,v);
}
void add(int p,int v){
    int _=Bin(a[p]);
    for(int i=p;i<=n;i+=lowbit(i))
        ins(root[i],1,m,_,v);//1...m
}
int cur[N],ql,qr;
int sum(int p){
    int ret=0;
    for(int i=p;i;i-=lowbit(i)) ret+=t[t[cur[i]].lc].w;//lc
    return ret;
}
int query(int l,int r,int k){//printf("query %d %d %d\n",l,r,k);
    if(l==r) return l;
    int ls=sum(qr)-sum(ql-1),mid=(l+r)>>1;
    if(k<=ls){
        for(int i=ql-1;i;i-=lowbit(i)) cur[i]=t[cur[i]].lc;
        for(int i=qr;i;i-=lowbit(i)) cur[i]=t[cur[i]].lc;
        return query(l,mid,k);
    }else{
        for(int i=ql-1;i;i-=lowbit(i)) cur[i]=t[cur[i]].rc;
        for(int i=qr;i;i-=lowbit(i)) cur[i]=t[cur[i]].rc;
        return query(mid+1,r,k-ls);
    }
}
void solve(){
    cnt=0;
    memset(root,0,sizeof(root));
    for(int i=1;i<=n;i++) add(i,1);
    for(int i=1;i<=Q;i++){
        if(q[i].s[0]==Q){
            ql=q[i].i,qr=q[i].j;
            for(int i=ql-1;i;i-=lowbit(i)) cur[i]=root[i];
            for(int i=qr;i;i-=lowbit(i)) cur[i]=root[i];
            printf("%d\n",mp[query(1,m,q[i].k)]);
        }else{
            add(q[i].x,-1);
            a[q[i].x]=q[i].d;
            add(q[i].x,1);
        }
    }
}
int main(int argc, const char * argv[]) {
    int T=read();
    while(T--){
        //init
        m=0;memset(mp,0,sizeof(mp));
        n=read();Q=read();
        for(int i=1;i<=n;i++) a[i]=mp[++m]=read();
        for(int i=1;i<=Q;i++){
            scanf("%s",q[i].s);
            if(q[i].s[0]==Q) q[i].i=read(),q[i].j=read(),q[i].k=read();
            else q[i].x=read(),q[i].d=mp[++m]=read();
        }
        sort(mp+1,mp+1+m);
        int p=0;mp[++p]=mp[1];
        for(int i=2;i<=m;i++) if(mp[i]!=mp[i-1]) mp[++p]=mp[i];
        m=p;
        //for(int i=1;i<=m;i++) printf("mp %d\n",mp[i]);
        solve();
    }
    
    return 0;
}

 

以上是关于带修改的主席树的主要内容,如果未能解决你的问题,请参考以下文章

Luogu Dynamic Ranking (带修改的主席树)

zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树

不带修改的主席树

模板 带修改主席树

BZOJ 2120: 数颜色 带修改的莫队算法 树状数组套主席树

POJ2104 K-th Number 不带修改的主席树 线段树