题目大意:给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文
题解:树上每个结点建一棵权值线段树记录其到根所有点的权值
查询(a,b)时,查询的是线段树a+线段树b-线段树lca(a,b)-线段树father[lca(a,b)],在权值线段树上求第k小即可
我的收获:常规操作……
#include <bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for(int i=(x);i<=(y);i++)
#define gep(i,x,y) for(int i=(x);i>=(y);i--)
const int N=100005;
const int L=20;
int n,m,last,cnt,sz;
int v[N],tmp[N];
int fa[N][L+2];
int dep[N],root[N];
vector<int> E[N];
namespace ChairmanTree{
int tl[N*50],tr[N*50],sum[N*50];
void update(int x,int &now,int l,int r,int k){
now=++sz;sum[now]=sum[x]+1,tl[now]=tl[x],tr[now]=tr[x];
if(l==r) return ;
int mid=(l+r)>>1;
if(k<=mid) update(tl[x],tl[now],l,mid,k);
else update(tr[x],tr[now],mid+1,r,k);
}
int query(int a,int b,int c,int d,int l,int r,int k){
if(l==r) return l;
int mid=(l+r)>>1;
int t=sum[tl[a]]+sum[tl[b]]-sum[tl[c]]-sum[tl[d]];
if(t>=k) return query(tl[a],tl[b],tl[c],tl[d],l,mid,k);
return query(tr[a],tr[b],tr[c],tr[d],mid+1,r,k-t);
}
}
void predfs(int x)
{
ChairmanTree::update(root[fa[x][0]],root[x],1,cnt,v[x]);
rep(i,1,L) fa[x][i]=fa[fa[x][i-1]][i-1];
rep(i,0,E[x].size()-1){
int v=E[x][i];
if(v==fa[x][0]) continue;
dep[v]=dep[x]+1,fa[v][0]=x;
predfs(v);
}
}
int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
rep(i,0,L) if((dep[x]-dep[y])&(1<<i)) x=fa[x][i];
if(x==y) return x;
gep(i,L,0) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
void work()
{
int x,y,z;
rep(i,1,m)
{
scanf("%d%d%d",&x,&y,&z);x^=last;
int c=lca(x,y);
last=tmp[ChairmanTree::query(root[x],root[y],root[c],root[fa[c][0]],1,cnt,z)];
printf("%d",last);
if(i!=m) putchar('\n');
}
}
void init()
{
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%d",&v[i]),tmp[i]=v[i];
sort(tmp+1,tmp+1+n);cnt=unique(tmp+1,tmp+1+n)-tmp-1;
rep(i,1,n) v[i]=lower_bound(tmp+1,tmp+1+cnt,v[i])-tmp;
int x,y;rep(i,2,n) scanf("%d%d",&x,&y),E[x].push_back(y),E[y].push_back(x);
predfs(1);
}
int main()
{
init();
work();
return 0;
}