主席树模板(待整理

主席树求区间第k大

    #include<stdio.h>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define lson l,mid
    #define rson mid+1,r
    const int maxn=1e5+5;
    int L[maxn<<5],R[maxn<<5],sum[maxn<<5];
    int tot;
    int a[maxn],T[maxn],Hash[maxn];//T[i]保存每颗主席树的根节点
    int build(int l,int r)
    {
        int rt=(++tot);
        sum[rt]=0;
        if(l<r)
        {
            int mid=(l+r)>>1;
            L[rt]=build(lson);
            R[rt]=build(rson);
        }
        return rt;
    }
    int update(int pre,int l,int r,int x)
    {
        int rt=(++tot);
        L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+1;
        if(l<r)
        {
            int mid=(l+r)>>1;
            if(x<=mid) L[rt]=update(L[pre],lson,x);
            else R[rt]=update(R[pre],rson,x);
        }
        return rt;
    }
    int query(int u,int v,int l,int r,int k)
    {
        if (l>=r) return l;
        int mid=(l+r)>>1;
        int num=sum[L[v]]-sum[L[u]];//前缀和操作
        if(num>=k) return query(L[u],L[v],lson,k);
        else return query(R[u],R[v],rson,k-num);
    }
    int main()
    {
         tot=0;
         int n,m;
         scanf("%d%d",&n,&m);
         for(int i=1;i<=n;i++)
         {
             scanf("%d",&a[i]);
             Hash[i]=a[i];
         }
         sort(Hash+1,Hash+1+n);
         int d=unique(Hash+1,Hash+1+n)-Hash-1;
         T[0]=build(1,d);
         for(int i=1;i<=n;i++)
         {
             int x=lower_bound(Hash+1,Hash+1+d,a[i])-Hash;//获取hash之后的代表值
             T[i]=update(T[i-1],1,d,x);
         }
         while(m--)
         {
             int l,r,k;
             scanf("%d%d%d",&l,&r,&k);
             int x=query(T[l-1],T[r],1,d,k);
             printf("%d\n",Hash[x]);
         }
         return 0;
    }

求区间内不同数的个数

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define lson l,mid
#define rson mid+1,r
const int maxn=3e5+5;
int vis[maxn<<5];
int L[maxn<<5],R[maxn<<5],sum[maxn<<5];
int tot;
int a[maxn],T[maxn];
int build(int l,int r)
{
    int rt=(++tot);
    sum[rt]=0;
    if(l<r)
    {
        int mid=(l+r)>>1;
        L[rt]=build(lson);
        R[rt]=build(rson);
    }
    return rt;
}
int update(int pre,int l,int r,int x,int v)
{
    int rt=(++tot);
    L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+v;
    if(l<r)
    {
        int mid=(l+r)>>1;
        if(x<=mid) L[rt]=update(L[pre],lson,x,v);
        else R[rt]=update(R[pre],rson,x,v);
    }
    return rt;
}
int query(int u,int v,int l,int r)
{
    if(l==u)
    {
        return sum[v];
    }
    int ans=0;
    int mid=(l+r)>>1;
    if(u<=mid) ans+=sum[R[v]],ans+=query(u,L[v],lson);//若访问左儿子,右边肯定都存在
    else ans+=query(u,R[v],rson);//访问右儿子
    return ans;
}
int main()
{
     tot=0;
     int n,m;
     scanf("%d",&n);
     for(int i=1;i<=n;i++)
     {
         scanf("%d",&a[i]);
     }
     T[0]=build(1,n);
     for(int i=1;i<=n;i++)
     {
         if(!vis[a[i]]) T[i]=update(T[i-1],1,n,i,1);
         else
         {
             int tmp=update(T[i-1],1,n,vis[a[i]],-1);//去除上一个位置的贡献,以免重复,tmp为上个位置去掉a[i]贡献之后的新根
             T[i]=update(tmp,1,n,i,1);//加上当前位置的贡献
         }
         vis[a[i]]=i;
     }
     scanf("%d",&m);
     while(m--)
     {
         int l,r;
         scanf("%d%d",&l,&r);
         int x=query(l,T[r],1,n);//查询r状态的树中以l为限制的不重复个数
         printf("%d\n",x);
     }
     return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38891827/article/details/80358970