题意
询问树上路径第k小点权。
题解
算是主席树模板题。
按点权的值域建线段树,遍历一趟树,对每个节点记下它到根节点的信息。
显然,从x到y的信息=从x到根的信息+从y到根的信息-从
lca(x,y)
到根的信息-从
fa(lca(x,y))
到根的信息。
直接在对应的树上找第k小即可。记得要离散。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=100005, maxe=200005;
typedef long long LL;
struct node{
int L,R,sum; node* ch[2];
node(int x1=0,int x2=0,int x3=0,node* x4=NULL){ L=x1; R=x2; sum=x3; ch[0]=ch[1]=x4; }
void maintain(){ sum=ch[0]->sum+ch[1]->sum; }
} nil, *null=&nil;
void init_null(){ null->sum=0; null->ch[0]=null->ch[1]=null; }
typedef node* P_node;
P_node Updata(P_node pre,int val){
P_node p=new node(pre->L,pre->R,pre->sum,null);
p->ch[0]=pre->ch[0]; p->ch[1]=pre->ch[1];
if(p->L==p->R){ p->sum++; return p; }
int mid=(p->L+p->R)>>1;
if(val<=mid) p->ch[0]=Updata(p->ch[0],val);
else p->ch[1]=Updata(p->ch[1],val);
p->maintain(); return p;
}
LL w[maxn],b[maxn];
int Query(P_node p1,P_node p2,P_node p3,P_node p4,int k){
if(p1->L==p1->R) return b[p1->L];
int suml=p1->ch[0]->sum+p2->ch[0]->sum-p3->ch[0]->sum-p4->ch[0]->sum;
if(suml>=k) return Query(p1->ch[0],p2->ch[0],p3->ch[0],p4->ch[0],k);
return Query(p1->ch[1],p2->ch[1],p3->ch[1],p4->ch[1],k-suml);
}
P_node build(int L,int R){
P_node p=new node(L,R,0,null);
if(L==R) return p;
int mid=(L+R)>>1;
p->ch[0]=build(L,mid); p->ch[1]=build(mid+1,R);
p->maintain(); return p;
}
int n,m,fir[maxn],nxt[maxe],son[maxe],tot;
int anc[maxn][20],dep[maxn];
void add(int x,int y){
son[++tot]=y; nxt[tot]=fir[x]; fir[x]=tot;
}
void dfs_LCA(int x,int pre){
anc[x][0]=pre; for(int i=1;i<=17;i++) anc[x][i]=anc[anc[x][i-1]][i-1];
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=pre) dep[son[j]]=dep[x]+1, dfs_LCA(son[j],x);
}
int getLCA(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
for(int i=17;i>=0;i--) if(dep[anc[x][i]]>=dep[y]) x=anc[x][i];
if(x==y) return x;
for(int i=17;i>=0;i--) if(anc[x][i]!=anc[y][i]) x=anc[x][i], y=anc[y][i];
return anc[x][0];
}
int find(LL x){
int L=1,R=b[0];
while(L<=R){
int mid=(L+R)>>1; if(b[mid]==x) return mid;
if(b[mid]<x) L=mid+1; else R=mid-1;
}
}
P_node rt[maxn];
void dfs(int x,int pre){
rt[x]=Updata(rt[pre],find(w[x]));
for(int j=fir[x];j;j=nxt[j]) if(son[j]!=pre) dfs(son[j],x);
}
LL getint(){
char ch=getchar(); LL res=0,ff=1;
while(!('0'<=ch&&ch<='9')){ if(ch=='-') ff=-1; ch=getchar(); }
while('0'<=ch&&ch<='9') res=res*10+ch-'0', ch=getchar();
return res*ff;
}
int main(){
freopen("bzoj2588.in","r",stdin);
freopen("bzoj2588.out","w",stdout);
init_null();
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) b[i]=w[i]=getint(); b[0]=n;
for(int i=1;i<=n-1;i++){
int x=getint(),y=getint();
add(x,y); add(y,x);
}
dfs_LCA(1,1);
sort(b+1,b+1+b[0]); b[0]=unique(b+1,b+1+b[0])-(b+1);
rt[0]=build(1,b[0]);
dfs(1,0);
LL last_ans=0;
while(m--){
LL x=getint(),y=getint(),z=getint(); x^=last_ans;
int lca=getLCA(x,y), lca_fa=lca==1?0:anc[lca][0];
printf("%lld",last_ans=Query(rt[x],rt[y],rt[lca],rt[lca_fa],z)); if(m) printf("\n");
}
return 0;
}