2588: Spoj 10628. Count on a tree

本文介绍了一种使用主席树进行树链上节点查询的方法。通过BFS遍历树并将节点加入主席树,实现了对树链(x,y)上第k大元素的高效查询。文章包含完整的代码实现。

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

按BFS序把树上的节点依次加入主席树,然后对于树链(x,y),用x+y-lca(x,y)-pre[lca(x,y)]的方法取出来,然后查询第k大即可。
幸福来得太突然,还没查就AC了,感觉脑子都还是糊的。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<set>
#include<map>
using namespace std;
#define rep(i,j,k) for(i=j;i<=k;++i)
#define per(i,j,k) for(i=j;i>=k;--i)
#define G getchar()
#define LL long long
#define pll pair<int,int>
#define mkp make_pair
#define X first
#define Y second
#define cl T[num].lc
#define cr T[num].rc
const int N=100005;
int n,m,w0[N],w[N],sa[N],ans;
int tot,he[N],ne[N<<1],to[N<<1];
int q[N],bfn[N];bool inq[N];
struct TREE{int sum,lc,rc;}T[2000000];int id,rt[N];
int dad[N],son[N],pre[N],dep[N],sz[N];
void read(int &x){
	char ch=G;
	while(ch<48||ch>57)ch=G;
	for(x=0;ch>47&&ch<58;ch=G)x=x*10+ch-48;
}
bool cmp(int x,int y){
	return w0[x]<w0[y];
}
void add(int x,int y){
	to[++tot]=y;ne[tot]=he[x];he[x]=tot;
}
void up(int num){
	T[num].sum=T[cl].sum+T[cr].sum;
}
void ins(int old,int x,int l,int r,int &num){
	if(!num)num=++id;
	if(l==r){T[num].sum=1;return;}
	int mid=l+r>>1;
	if(x<=mid)ins(T[old].lc,x,l,mid,cl),cr=T[old].rc;
	else ins(T[old].rc,x,mid+1,r,cr),cl=T[old].lc;
	up(num);
}
void BFS(){
	int Ft=1,Rr=2,i,u,v;
	for(inq[q[1]=1]=1;Ft<Rr;){
		bfn[u=q[Ft]]=Ft;
		ins(rt[bfn[pre[u]]],w[u],1,n,rt[Ft++]);
		for(i=he[u];i;i=ne[i])if(!inq[v=to[i]])
			inq[q[Rr++]=v]=1;
	}
}
void DFS1(int x,int e){
	int i,y;dep[x]=dep[pre[x]=to[e]]+1;sz[x]=1;
	for(i=he[x];i;i=ne[i])if(i!=e){
		DFS1(y=to[i],i^1);
		if(sz[son[x]]<sz[y])son[x]=y;
		sz[x]+=sz[y];
	}
}
void DFS2(int x){
	int i,y;
	dad[x]=son[pre[x]]==x?dad[pre[x]]:x;
	if(son[x])DFS2(son[x]);
	for(i=he[x];i;i=ne[i])if(!dad[y=to[i]])
		DFS2(y);
}
int lca(int x,int y){
	int fx=dad[x],fy=dad[y];
	while(fx!=fy)
		if(dep[fx]>dep[fy])fx=dad[x=pre[fx]];
		else fy=dad[y=pre[fy]];
	return dep[x]<dep[y]?x:y;
}
int query(int k,int x1,int x2,int x3,int x4,int l,int r){
	if(l==r)return l;
	int mid=l+r>>1,tmp=T[T[x1].lc].sum+T[T[x2].lc].sum-T[T[x3].lc].sum-T[T[x4].lc].sum;
	if(k>tmp)return query(k-tmp,T[x1].rc,T[x2].rc,T[x3].rc,T[x4].rc,mid+1,r);
	return query(k,T[x1].lc,T[x2].lc,T[x3].lc,T[x4].lc,l,mid);
}
int main(){
	int i,x,y,k,z;
	read(n);read(m);
	rep(i,1,n)read(w0[sa[i]=i]);
	sort(sa+1,sa+n+1,cmp);
	rep(i,1,n)w[sa[i]]=i;
	tot=1;
	rep(i,2,n){
		read(x);read(y);
		add(x,y);add(y,x);
	}
	DFS1(1,0);DFS2(1);
	rt[0]=id=1;BFS();
	while(m--){
		read(x);read(y);read(k);z=lca(x^=ans,y);
		ans=query(k,rt[bfn[x]],rt[bfn[y]],rt[bfn[z]],rt[bfn[pre[z]]],1,n);
		printf("%d",ans=w0[sa[ans]]);if(m)puts("");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值