POJ 2104 K-th Number 主席树(求区间第k大)

点击打开链接

主席书资料

题意:给出n个数,m次询问,[x,y]内第k小的数时多少?n<=1e5,m<=5000

主席树:对原序列的每个前缀i都建立一个线段树 维护值域[l,r]中的每个数,在前缀i的出现次数.

此时l,r不在表示为下标,l,r为第l~r小的数

先将原序列离散化后,更新出主席树

求[x,y]内第k大的数?
若第1~mid大的数在[x,y]中出现的次数sum>=k,则[x,y]的第k大就在左子树中,否则[x,y]第k大为右子树的第k-sum个
由于主席树保存了第l~r大的数在任意前缀y和x-1的的出现次数,则第l~mid大的数在区间[x,y]的出现次数为T[T[y].l].sum-T[T[x-1].l].sum

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N=2e5+20;
int n,m,a[N],x,y,k;
int root[N],cnt;
struct node{
	int l,r,sum; 
	//此时l,r不在表示下标,sum表示第l~r大的数的出现次数
}T[N*40];
vector<int> v;
int getid(int x)//离散化 
{
	return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int build(int l,int r)
{
	int rt=++cnt;
	T[rt].sum=0;
	T[rt].l=T[rt].r=0;
	if(l==r) return rt;
	int mid=(l+r)>>1;
	T[rt].l=build(l,mid);//l保存左子树结点号
	T[rt].r=build(mid+1,r); 
	return rt;
}
void update(int l,int r,int &x,int y,int k)//根据第i个数是第几大来更新 
{
	T[++cnt]=T[y],T[cnt].sum++,x=cnt;
	if(l==r) return;
	int mid=(l+r)>>1;

	if(mid>=k) 
	update(l,mid,T[x].l,T[y].l,k);
	else
	update(mid+1,r,T[x].r,T[y].r,k);
}  

int query(int l,int r,int x,int y,int k)
{
	if(l==r) return l; 
	int mid=(l+r)>>1;
	int sum=T[T[y].l].sum-T[T[x].l].sum;
	if(sum>=k)
	return query(l,mid,T[x].l,T[y].l,k);
	else
	return query(mid+1,r,T[x].r,T[y].r,k-sum); 
}
int main()
{
	while(cin>>n>>m)
	{
		cnt=0;
		build(1,n);
		v.clear();
		for(int i=1;i<=n;i++)
			scanf("%d",&a[i]),v.push_back(a[i]);
		sort(v.begin(),v.end());
		v.erase(unique(v.begin(),v.end()),v.end());
		
		 
		for(int i=1;i<=n;i++)//前缀1~i和1~i-1只有一条链不同,那么root[i]其它结点只要用前一棵树的结点即可 
			update(1,n,root[i],root[i-1],getid(a[i]));	// 
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&x,&y,&k);
			int ans=query(1,n,root[x-1],root[y],k);	
			printf("%d\n",v[ans-1]);//输出第k大离散化前的值 
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值