首页 > 代码库 > 主席树

主席树

POJ 2104 这题说的是给了一个区间求区间的第K大的数, 这点利用 函数式线段树的前缀式线段是的 长处 解决, 我们将 每个数字离散一下, 然后线段树存的是他的孩子个数,然后利用函数式线段树的前缀思想 两个前缀相减便得到了我们想要的 区间中的点的个数

#include <iostream>#include <string.h>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;const int maxn=7000005;const int MA = 100005;int Ls[maxn],Rs[maxn],num[maxn],T[MA],len;int dd[MA],vv[MA];void insert(int L, int R, int k, int pre, int &x){      x = ++len;      Ls[x]=Ls[pre];      Rs[x]=Rs[pre];      num[x]=num[pre]+1;      if(L==R) return ;      int mid=(L+R)>>1;      if(k<=mid) insert(L,mid,k,Ls[pre],Ls[x]);      else insert(mid+1,R,k,Rs[pre],Rs[x]);}int query(int L, int R,int K, int pre,int cur){       if(L==R) return L;      int mid = (L+R)>>1;      if(num[ Ls[cur] ]-num[ Ls[pre] ]>=K)        return query(L,mid,K,Ls[pre],Ls[cur]);      else return query( mid+1, R, K - (num[Ls[cur]]-num[Ls[pre]]),Rs[pre],Rs[cur]);}int main(){    int n,m;    while(scanf("%d%d",&n,&m)==2){         for(int i =0; i< n; ++i){             scanf("%d",&dd[i]);             vv[i]=dd[i];         }         sort(vv,vv+n);         int vk= unique(vv,vv+n)-vv;         T[0]=Ls[0]=Rs[0]=num[0]=len=0;         for(int i =0; i<n;i++){               int loc = lower_bound(vv,vv+vk,dd[i])-vv+1;               insert(1,vk,loc,T[i],T[i+1]);         }         while(m--){               int L,R,K;               scanf("%d%d%d",&L,&R,&K);               int ans=query(1,vk,K,T[L-1],T[R]);               printf("%d\n",vv[ans-1]);         }    }    return 0;}
View Code

 zoj 2112 主席树+树状数组 这题说的是给了一个数组 然后 有两种操作第一种操作 是查询 【L,R】 中的第K 大的数 , 第二种操作是 将x位置的值改为k, 这样同样利用 主席树前缀线段树的想法做好后,我们 用一个树状数组对它进行更改, 我们知道 在树状数组的 中 每个点就是一课树 然 后 通 过 不 断 地 去 更 改 这 树状数组的的 lowbit的树 结果求得了这个区间的 值

计算式 sum(R)-sum(L)+num(ls[rr])-num[rx[ll]]; 判断是进入左子树还是右子树

#include <iostream>#include <cstdio>#include <string.h>#include <cmath>#include <algorithm>using namespace std;const int maxn = 1009000 ;const int MM = 60005;struct Que{   int kind,L,R,K;}Q[10005];int dd[50005],vv[MM],T[50005],Ls[maxn],Rs[maxn],num[maxn],len,S[50005],use[50005];int n,m,vk;void insert(int L, int R, int loc, int v, int pre, int &x ){      x=++len;      Ls[x] = Ls[ pre ];      Rs[x] = Rs[ pre ];      num[x] =   num[ pre ] + v ;      if( L == R )return;      int mid = ( L + R ) >> 1;      if( loc <= mid ) insert( L, mid, loc, v, Ls[pre], Ls[x] );      else insert( mid+1, R, loc, v, Rs[pre], Rs[x] );}int lowbit( int x ){  return x&(-x);}int sum(int x){   int ans=0;   while(x>0){      ans += num[ Ls[ use[ x ] ] ];      x -= lowbit(x);   }   return ans;}void modie( int x, int loc, int v ){     while(x<=n){         insert( 0, vk-1, loc, v, S[x], S[x] );         x+=lowbit(x);     }}int query(int L, int R, int left , int right, int K ,int LL, int RR){      if(L==R) return L;      int mid =(L+R)>>1;      int nm = sum(right) - sum(left) + num[ Ls[RR] ] - num[ Ls[LL] ];      if(nm>=K){          for(int i = left; i ; i -=lowbit(i))            use[i]=Ls[use[i]];          for(int i = right; i ; i -= lowbit(i) )            use[i]=Ls[use[i]];          return query( L, mid, left, right, K, Ls[LL] ,Ls[RR] );      }else{         for( int i = left ; i ; i -= lowbit(i) )            use[i]=Rs[ use[i] ];         for(int i= right ; i ; i-=lowbit(i) )            use[i]=Rs[ use[i] ];         return query(mid+1,R,left, right, K-nm, Rs[LL] ,Rs[RR] );      }}int main(){      int c;      scanf("%d",&c);      while(c--){            scanf("%d%d",&n,&m);        vk=0;        memset(S,0,sizeof(S));        for(int i=1; i<=n; ++i){             scanf("%d",&dd[i]);             vv[vk++]=dd[i];        }        char op[10];        for(int i =0; i < m; ++i){             scanf("%s",op);             if(op[0]==Q){                Q[i].kind=0;                scanf("%d%d%d",&Q[i].L,&Q[i].R,&Q[i].K);             }else{                 Q[i].kind=1;                 scanf("%d%d",&Q[i].L,&Q[i].R);                 vv[vk++] = Q[i].R;             }        }        sort(vv,vv+vk);        vk=unique(vv,vv+vk)-vv;        T[0]=Rs[0]=Ls[0]=num[0]=len=0;        for(int i=1; i<=n; i++)        {             int loc = lower_bound(vv,vv+vk,dd[i])-vv;             insert(0,vk-1,loc,1,T[i-1],T[i]);        }        for( int i = 0; i < m; ++ i )        {             if(Q[i].kind==0){                int LL=Q[i].L-1;                int RR=Q[i].R;                int K =Q[i].K;                for(int i=LL ; i; i-=lowbit(i))                    use[i]=S[i];                for(int i=RR ; i ; i-=lowbit(i) )                    use[i]=S[i];                int ans = query(0, vk-1, LL, RR, K, T[LL], T[RR]);                printf("%d\n",vv[ans]);             }else{                int loc = lower_bound( vv , vv + vk , dd[Q[i].L] ) - vv ;                modie( Q[i].L, loc , -1 );                    loc = lower_bound( vv  , vv+vk , Q[i].R ) - vv ;                modie( Q[i].L, loc , 1 );                dd[Q[i].L] = Q[i].R;             }        }      }     return 0;}
View Code

 

主席树