洛谷P2633 Count on a tree(RE)

本文介绍了一种基于树状结构的数据处理方法,利用离线预处理的方式进行路径查询优化。通过对节点进行预处理,构建了支持快速查询的辅助数据结构,并通过实际案例展示了如何在给定的树形结构中高效地进行范围查询。

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

#include<stdio.h>
#include<algorithm>
#define N 100005
using namespace std;
int n,m,x,y,z,last,w[N],s[N],len;
int head[N],next[N<<1],to[N<<1];
int pre[N][20],dep[N];
int rt[N],ch[N*20][2],size[N*20],tot;
void add(int a,int b) {
	static int cnt=0;
	to[++cnt]=b;
	next[cnt]=head[a];
	head[a]=cnt;
}
void build0(int &t,int l,int r) {
	t=++tot;
	if(l<r) {
		int mid=l+r>>1;
		if(l<=mid) build0(ch[t][0],l,mid);
		if(mid<r) build0(ch[t][1],mid+1,r);
	}
}
void build(int &t,int nxt,int v,int l,int r) {
	t=++tot;
	size[t]=size[nxt]+1;
	if(l<r) {
		int mid=l+r>>1,d=(v>mid);
		build(ch[t][d],ch[nxt][d],v,(d?mid+1:l),(d?r:mid));
		ch[t][!d]=ch[nxt][!d];
	}
}
void dfs(int u,int p,int d) {
	pre[u][0]=p;
	dep[u]=d;
	build(rt[u],rt[p],lower_bound(s+1,s+1+len,w[u])-s,1,len);
	for(int i=head[u]; i; i=next[i]) {
		if(to[i]!=p) dfs(to[i],u,d+1);
	}
}
void setpre() {
	for(int i=1; i<20; i++) {
		for(int j=1; j<=n; j++) {
			pre[j][i]=pre[pre[j][i-1]][i-1];
		}
	}
}
int lca(int a,int b) {
	if(dep[a]<dep[b]) swap(a,b);
	int delt=dep[a]-dep[b];
	for(int i=19; i>=0; i--) if((1<<i)&delt) a=pre[a][i];
	if(a==b) return a;
	for(int i=19; i>=0; i--) {
		if(pre[a][i]!=pre[b][i])
			a=pre[a][i], b=pre[b][i];
	}
	return pre[a][0];
}
int query(int o,int p,int q,int k,int l,int r) {
	if(l==r) return l;
	int mid=l+r>>1,tmp=size[ch[p][0]]+size[ch[q][0]]-size[ch[o][0]]-size[pre[ch[o][0]][0]];
	if(k<=tmp) return query(ch[o][0],ch[p][0],ch[q][0],k,l,mid);
	else return query(ch[o][1],ch[p][1],ch[q][1],k-tmp,mid+1,r);
}
int main() {
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++) scanf("%d",&w[i]), s[i]=w[i];
	for(int i=1; i<n; i++) scanf("%d%d",&x,&y), add(x,y), add(y,x);
	sort(s+1,s+1+n);
	len=unique(s+1,s+1+n)-s-1;
	build0(rt[0],1,len);
	dfs(1,0,1);
	setpre();
	while(m--) {
		scanf("%d%d%d",&x,&y,&z);
		x^=last;
		printf("%d\n",last=s[query(rt[lca(x,y)],rt[x],rt[y],z,1,len)]);
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值