题目大意
给出一棵树,询问两点路径上第k大点权是什么。
解题思路
自上到下建可持久化线段树,维护当前点到根的信息,使用权值线段树记录size,查询的时候两端的值减去lca和lca的父亲的值即当前路径的权值线段树,即可求解。
code
using namespace std;
int const MxN=1e5+100,MxA=2147483647;
int N,M,Edge,Node,Mx,A[MxN+9],Begin[MxN+9],Dep[MxN+9],Fa[MxN+9][25],To[MxN*2+9],Next[MxN*2+9],Size[MxN*40+9],Son[MxN*40+9][2];
void Insert(int U,int V){
To[++Edge]=V;
Next[Edge]=Begin[U];
Begin[U]=Edge;
}
void Oper(int Pre,int Now,int L,int R,int V){
int Mid=(1ll*L+R)>>1,P=(V<=Mid)?0:1;
Size[Now]=Size[Pre]+1;
if(L==R)return;
Son[Now][!P]=Son[Pre][!P];
Son[Now][P]=++Node;
if(P)L=Mid+1;else R=Mid;
Oper(Son[Pre][P],Son[Now][P],L,R,V);
}
void Dfs(int Now,int Pre){
Dep[Now]=Dep[Pre]+1;
Oper(Pre,Now,1,MxA,A[Now]);
for(int i=Begin[Now];i;i=Next[i])if(To[i]!=Pre)Fa[To[i]][0]=Now,Dfs(To[i],Now);
}
int Lc(int U,int V){
if(Dep[U]<Dep[V])swap(U,V);
Fd(i,Mx,0)if(Dep[Fa[U][i]]>=Dep[V])U=Fa[U][i];
if(U==V)return U;
Fd(i,Mx,0)if(Fa[U][i]!=Fa[V][i])U=Fa[U][i],V=Fa[V][i];
return Fa[U][0];
}
int Qury(int U,int V,int Lca,int FaLca,int L,int R,int K){
int Mid=(1ll*L+R)>>1,Tmp,P=((Tmp=Size[Son[U][0]]+Size[Son[V][0]]-Size[Son[Lca][0]]-Size[Son[FaLca][0]])>=K)?0:1;
if(L==R)return L;
if(P)L=Mid+1,K-=Tmp;else R=Mid;
return Qury(Son[U][P],Son[V][P],Son[Lca][P],Son[FaLca][P],L,R,K);
}
int main(){
//freopen("d.in","r",stdin);
//freopen("d.out","w",stdout);
scanf("%d%d",&N,&M);Node=N;
Fo(i,1,N)scanf("%d",&A[i]);
int U,V;
Fo(i,2,N){
scanf("%d%d",&U,&V);
Insert(U,V);Insert(V,U);
}
Dfs(1,0);int K,Lca;Mx=log(N)/log(2);
Fo(j,1,Mx)Fo(i,1,N)Fa[i][j]=Fa[Fa[i][j-1]][j-1];
Fo(i,1,M){
scanf("%d%d%d",&U,&V,&K);Lca=Lc(U,V);
printf("%d\n",Qury(U,V,Lca,Fa[Lca][0],1,MxA,K));
}
return 0;
}