[Data]带修改的主席树[树状数组套主席树]

  树状数组套主席树

树状数组的每个节点维护的是一段区间,我们将每个区间构造成一棵线段树,这时候如果我们要修改一个值,只需要修改logn个节点即可,

时间复杂度为log^2(n),树状数组维护的区间是数的个数n;离散化时是把所有数(包括要修改的数)全部离散化;

1.修改

在修改之前,我们应先把序列里原来的值在主席树对应节点+1(主席树里维护的是某个数出现的次数),遍历logn棵主席树。在修改时,先把该

数原来的值的在主席树上的对应节点+(-1),再把要修改的值在对应节点+1,并在原数组上修改;

2.查询区间K大

其实查询和普通主席树在原理上并没有什么区别,都是用二分,然后树套树就是把一个区间的主席树拆成了若干部分,(由树状数组来完成),

例:我们要查询区间[l,r]第k大,用一个数组来记录从1到l要经过的每棵主席树的根节点,再用另一个数组来记录从1到r要经过的每棵主席树的

根节点,利用前缀和思想,在查询时先把第一个数组的值的sum累加起来,另一个也一样,两个数组作差,得到的就是区间l到r的数出现的个数,

然后再用二分不断缩小范围,直至l==r;

luogu 2617:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #define lowbit(x) x&-x
  5 using namespace std;
  6 #define maxn  10005
  7 int totn=0,cnt=0,a[maxn*2],s[maxn<<1],ls[maxn*600],rs[maxn*600],val[maxn*600],rt[maxn*600],sz=0,ca[maxn*2],cb[maxn*2],totx,toty,n,xx[maxn],yy[maxn],cc[maxn];
  8 //void build(int &p,int l,int r){
  9 //    p=++cnt;
 10 //    if(l!=r){
 11 //        int mid=(l+r)/2;
 12 //        build(ls[p],l,mid);
 13 //        build(rs[p],mid+1,r);
 14 //    }
 15 //}
 16 void insert(int &p,int cmp,int x,int l,int r,int v){
 17     p=++cnt;ls[p]=ls[cmp];rs[p]=rs[cmp];val[p]=val[cmp]+v;
 18     if(l!=r){
 19         int mid=(l+r)/2;
 20         if(x<=mid){
 21             insert(ls[p],ls[cmp],x,l,mid,v);
 22         }
 23         else{
 24             insert(rs[p],rs[cmp],x,mid+1,r,v);
 25         }
 26     }
 27 }
 28 int query(int l,int r,int k){
 29     int i;
 30     if(l==r) return l;
 31     int sum=0,mid=l+r>>1;
 32     for(int i=1;i<=totx;i++) sum-=val[ls[xx[i]]];
 33     for(int i=1;i<=toty;i++) sum+=val[ls[yy[i]]];
 34     if(k<=sum) {
 35         for(i=1;i<=totx;i++) xx[i]=ls[xx[i]];
 36         for(i=1;i<=toty;i++) yy[i]=ls[yy[i]];
 37         return query(l,mid,k);}
 38     else {
 39         for(int i=1;i<=totx;i++) xx[i]=rs[xx[i]];
 40         for(int i=1;i<=toty;i++) yy[i]=rs[yy[i]];
 41         return query(mid+1,r,k-sum); }
 42 }
 43 void add(int x,int v){
 44     int k=lower_bound(s+1,s+totn+1,a[x])-s;
 45     for(int i=x;i<=n;i+=lowbit(i)) insert(rt[i],rt[i],k,1,totn,v);
 46 }
 47 int read(){
 48     int s=0;
 49     char c;
 50     while(c<'0'||c>'9') c=getchar();
 51     while(c>='0'&&c<='9'){
 52         s=s*10+c-48;
 53         c=getchar();
 54     }
 55     return s;
 56 }
 57 int main()
 58 {
 59     int m,l,r,k,i;
 60     char ch;
 61     n=read();m=read();
 62     for(i=1;i<=n;i++){
 63         a[i]=read();
 64         s[++totn]=a[i];
 65     }
 66     for(i=1;i<=m;i++){
 67         scanf(" %c",&ch);//scanf("%d%d",&ca[i],&cb[i]);
 68         ca[i]=read();cb[i]=read();
 69         if(ch=='Q') cc[i]=read();
 70         //scanf("%d",&cc[i]);
 71         else{
 72             s[++totn]=cb[i];
 73         }
 74     }
 75     sort(s+1,s+totn+1);
 76     sz=unique(s+1,s+totn+1)-s-1;
 77     for(i=1;i<=n;i++)
 78     add(i,1);
 79 //    build(rt[0],1,sz);
 80 //    for(i=1;i<=n;i++){
 81 //        insert(rt[i],rt[i-1],lower_bound(s+1,s+sz+1,a[i])-s,1,sz);
 82 //    }
 83 //    for(i=1;i<=m;i++){
 84 //        scanf("%d%d%d",&l,&r,&k);
 85 //        printf("%d
",s[query(rt[l-1],rt[r],1,sz,k)]);
 86 //    }
 87     for(i=1;i<=m;i++){
 88         if(cc[i]){
 89             totx=0;
 90             toty=0;
 91             for(int j=ca[i]-1;j;j-=lowbit(j)) xx[++totx]=rt[j];
 92             for(int j=cb[i];j;j-=lowbit(j)) yy[++toty]=rt[j];
 93             printf("%d
",s[query(1,totn,cc[i])]);
 94         }
 95         else {
 96             add(ca[i],-1);
 97             a[ca[i]]=cb[i];
 98             add(ca[i],1);
 99         }
100     }
101 }
View Code

 

原文地址:https://www.cnblogs.com/Fish-/p/8168960.html