主席树求区间第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;
}