SPOJ 1487 Query on a tree III 主席树,可持续化线段树

本文介绍了一种离线查询方法,通过构建树状结构实现区间查询优化。利用离线预处理技术,该方法能在O(log N)时间内完成单次查询。文中详细解释了如何初始化、构建树状结构,并通过递归更新节点来维护区间信息,最后实现了快速查询特定位置的第k小元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <cstring>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <queue>
#include <string>
#include <set>
#include <stack>

using namespace std;
#define ll long long
#define eps 1e-8
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define mod 1000000007
#define sqr(x) ((x)*(x))
#define lson (u<<1)
#define rson (u<<1|1)
#define maxn 100100
#define maxm 200100
#pragma comment(linker,"/STACK:102400000,102400000")

int n,m;
int arr[maxn],num[maxn];
int lisan[maxn],cnt;
int tree[maxn*20],ls[maxn*20],rs[maxn*20],sum[maxn*20],tot;
int h[maxn],vv[maxm],nxt[maxm],e;
int lft[maxn],rht[maxn],id;
int q[maxn];
int ID[maxn];


void init()
{
	memset(h,-1,sizeof(h));
	e = 0;
	memset(lft,0,sizeof(lft));

}
void add(int u,int v)
{
	vv[e] = v, nxt[e] = h[u], h[u] = e++;
	vv[e] = u, nxt[e] = h[v], h[v] = e++;
}
void dfs(int u)
{
	lft[u] = ++id;
	for(int i=h[u];i+1;i=nxt[i])
	{
		if(lft[vv[i]]) continue;
		dfs(vv[i]);
	}
	rht[u] = id;

}
void build(int &rt,int l,int r)
{
	rt = ++tot;
	sum[rt] = 0;
	if(l==r) return;
	int mid = (l+r)>>1;
	build(ls[rt],l,mid);
	build(rs[rt],mid+1,r);
}
void update(int last,int &rt,int l,int r,int p)
{
	rt = ++tot;
	ls[rt] = ls[last],rs[rt] = rs[last], sum[rt] = sum[last] + 1;
	if(l==r) return;
	int mid = (l+r)>>1;
	if(p<=mid) update(ls[last],ls[rt],l,mid,p);
	else update(rs[last],rs[rt],mid+1,r,p);

}
int query(int ss,int tt,int l,int r,int k)
{
	if(l==r) return l;
	int cnt = sum[ls[tt]] - sum[ls[ss]];
	int mid = (l+r)>>1;
	if(cnt>=k)
		return query(ls[ss],ls[tt],l,mid,k);
	else
		return query(rs[ss],rs[tt],mid+1,r,k-cnt);

}
int getInt()
{
	char c;
	for(c=getchar();c<'0'||c>'9';c=getchar());
	int ret = c-'0';
	for(c=getchar();c>='0'&&c<='9';c=getchar())
		ret = ret*10+c-'0';
	return ret;
	
}
int main()
{
	init();
	tot = 0;
	int u,v,l,r,k;
	n = getInt();
	for(int i=1;i<=n;i++)
		arr[i] = getInt(),lisan[i] = arr[i];
	for(int i=1;i<n;i++)
		u = getInt(),v = getInt(), add(u,v);
	id = 0;
	dfs(1);
	sort(lisan+1,lisan+n+1);
	cnt = unique(lisan+1,lisan+n+1)-lisan-1;
	for(int i=1;i<=n;i++){
		num[lft[i]] = lower_bound(lisan+1,lisan+1+cnt,arr[i])-lisan;
		ID[num[lft[i]]] = i;
	}
	build(tree[0],1,cnt);
	for(int i=1;i<=n;i++)
		update(tree[i-1],tree[i],1,cnt,num[i]);
	m = getInt();

	while(m--)
	{
		u = getInt(),k = getInt();
		l = lft[u], r = rht[u];
		int idx = query(tree[l-1],tree[r],1,cnt,k);
		printf("%d\n",ID[idx]);
	}

	return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值