主席树模板(POJ2104)

离散化:
对数组排完序后用unique去重,unique返回的是去重后的数组的末地址,减去第一个元素的地址就能得到去重后的数组大小,用lower_bound查找原数字在排序去重后的序列中的位序,用位序代替数字完成离散化。

#include<cstdio>
#include<algorithm>
using namespace std;
#define lson l,m,ls[rt]
#define rson m+1,r,rs[rt] 
typedef long long ll;
const int maxn = 1e5 + 5;
int ls[maxn*30],rs[maxn*30],tot,rts[maxn];//tot为总结点数 
int t[maxn*30];
int a[maxn],num[maxn];

void build(int l,int r,int &rt)
{
	rt = ++tot;
	t[rt] = 0;//建一棵全为0的空树。 
	if(l==r)		
		return ;
	int m = l+r>>1;
	build(lson); 
	build(rson);
}

void add(int p,int C,int l,int r,int &rt,int lst)
{
	rt = ++tot;
	ls[rt] = ls[lst],rs[rt] = rs[lst];
	t[rt] = t[lst] + C;					//先从上一个版本的结点拷贝信息,因为传的是引用, 
	if(l==r)							//进入下一层递归时rt = ++tot;这一句会给新的结点编号。 
		return ;
	int m = l+r>>1;
	if(p<=m)
		add(p,C,lson,ls[rt]);
	else
		add(p,C,rson,rs[rt]);
}

int query(int x,int y,int l,int r,int k)
{
	if(l==r)
		return l;
	int c = t[ls[y]] - t[ls[x]];//c表示左子树中数字的数量 
	int m = l+r>>1;
	if(c>=k)//k<=c时,第k小是左子树中的第k小。
		return query(ls[x],ls[y],l,m,k);
	else//k>c时,第k小是右子树中的第k-c小 
		return query(rs[x],rs[y],m+1,r,k-c);	
}

int N,M,c,x,y,k;
int main()
{
	while(scanf("%d%d",&N,&M)!=EOF)
	{
		tot = 0;	
		for(int i=1;i<=N;++i)
		{
			scanf("%d",&a[i]);
			num[i] = a[i];
		}
		
		sort(num+1,num+N+1);
		int cnt = unique(num+1,num+N+1)-(num+1);
		build(1,cnt,rts[0]);
		for(int i=1;i<=N;++i)
			a[i] = lower_bound(num+1,num+cnt+1,a[i])-num;
		
		for(int i=1;i<=N;++i)
			add(a[i],1,1,cnt,rts[i],rts[i-1]);
					
		while(M--)
		{
			scanf("%d%d%d",&x,&y,&k);
			printf("%d\n",num[query(rts[x-1],rts[y],1,cnt,k)]);
		}
	}	
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值