题目描述
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
输入格式
第一行两个整数N,M。
第二行有N个整数,其中第i个整数表示点i的权值。
后面N-1行每行两个整数(x,y),表示点x到点y有一条边。
最后M行每行两个整数(u,v,k),表示一组询问。
输出格式
M行,表示每个询问的答案。
输入输出样例
输入 #1复制
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
0 5 2
10 5 3
11 5 4
110 8 2
输出 #1复制
2
8
9
105
7
说明/提示
HINT:
N,M<=100000
第k大,比较明显的主席树,但是是树上两点的问题。
我们可以想到,主席树是一个权值线段树的前缀和,所以我们可以利用树上差分+树上前缀和来解决这个问题。
如果会树上差分+主席树,那么就是一个sb题
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int n,m,q,a[N],b[N],cnt,f[N][20],lg[N],rt[N],h[N],res;
int head[N],nex[N<<1],to[N<<1],tot;
struct node{int l,r,sum;}t[N*20];
inline void add(int a,int b){
to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
}
void change(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) change(l,mid,t[x].l,t[y].l,k);
else change(mid+1,r,t[x].r,t[y].r,k);
}
int ask(int l,int r,int s1,int s2,int s3,int s4,int k){
if(l==r) return l; int mid=l+r>>1;
int s=t[t[s1].l].sum+t[t[s2].l].sum-t[t[s3].l].sum-t[t[s4].l].sum;
if(s>=k) return ask(l,mid,t[s1].l,t[s2].l,t[s3].l,t[s4].l,k);
else return ask(mid+1,r,t[s1].r,t[s2].r,t[s3].r,t[s4].r,k-s);
}
void dfs(int x,int fa){
h[x]=h[fa]+1; f[x][0]=fa;
change(1,m,rt[x],rt[fa],a[x]);
for(int i=1;(1<<i)<=h[x];i++) f[x][i]=f[f[x][i-1]][i-1];
for(int i=head[x];i;i=nex[i]){
if(to[i]==fa) continue;
dfs(to[i],x);
}
}
int lca(int x,int y){
if(h[x]<h[y]) swap(x,y);
while(h[x]>h[y]) x=f[x][lg[h[x]-h[y]]-1];
if(x==y) return x;
for(int i=lg[h[x]]-1;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
signed main(){
cin>>n>>q;
for(int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+1+m,a[i])-b;
for(int i=1;i<n;i++){
int u,v; scanf("%d %d",&u,&v); add(u,v); add(v,u);
}
dfs(1,0);
while(q--){
int u,v,k; scanf("%d %d %d",&u,&v,&k); u^=res; int fa=lca(u,v);
res=b[ask(1,m,rt[u],rt[v],rt[fa],rt[f[fa][0]],k)];
printf("%d\n",res);
}
return 0;
}