题解:
主席树是一个类似前缀和的数据结构,具有和前缀和类似的区间加减及差分等性质。
在求解线性区间的第k小数时,我们需要将该区间内的所有数值离散化后扔到一颗主席树中,并在这颗主席树上左右递归,来找到第k小数。
树上类似:用树上每个节点维护它到根的路径上的权值线段树,每个节点用它的父节点更新,dfs建树,套个差分就好了: t [ u ] + t [ v ] − t [ l c a ] − t [ l c a f a ] t[u] + t[v] - t[lca] - t[lca_fa] t[u]+t[v]−t[lca]−t[lcafa]
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+50;
struct node{ int v,nxt; }edge[MAXN<<1];
int head[MAXN],a[MAXN],b[MAXN],tot,ans,sz,cnt;
int dep[MAXN],dp[MAXN][20],rt[MAXN];
struct Node{ int l,r,sum; }t[MAXN*32];
inline void add(int u,int v){
edge[++tot].v=v; edge[tot].nxt=head[u]; head[u]=tot;
edge[++tot].v=u; edge[tot].nxt=head[v]; head[v]=tot;
}
void update(int l,int r,int &x,int y,int k){
x=++cnt; t[x]=t[y]; t[x].sum++;
if(l==r) return;
int mid=l+r>>1;
if(k<=mid) 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 u,int v,int fa,int pfa,int k){
if(l==r) return l;
int mid=l+r>>1;
int sum=t[t[u].l].sum+t[t[v].l].sum-t[t[fa].l].sum-t[t[pfa].l].sum;
if(sum>=k) return Query(l,mid,t[u].l,t[v].l,t[fa].l,t[pfa].l,k);
else return Query(mid+1,r,t[u].r,t[v].r,t[fa].r,t[pfa].r,k-sum);
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1; dp[u][0]=fa;
update(1,sz,rt[u],rt[fa],a[u]);
for(int i=1;i<20;i++) dp[u][i]=dp[dp[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].nxt){
int v = edge[i].v;
if(v==fa) continue;
dfs(v,u);
}
}
inline int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=19;i>=0;i--)
if(dep[dp[x][i]]>=dep[y])
x=dp[x][i];
if(x==y) return x;
for(int i=19;i>=0;i--)
if(dp[x][i]!=dp[y][i])
x=dp[x][i],y=dp[y][i];
return dp[x][0];
}
int main(){
//freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
int n,Q; scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+n+1); sz=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+sz+1,a[i])-b;
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),add(u,v);
dfs(1,0);
while(Q--){
int u,v,k; scanf("%d%d%d",&u,&v,&k);
u^=ans;
int fa=lca(u,v);
ans = b[Query(1,sz,rt[u],rt[v],rt[fa],rt[dp[fa][0]],k)];
printf("%d\n",ans);
}
return 0;
}