title
简化题意:
给你一棵有n个结点的树,节点编号为 \(1\sim n\)。每个节点都有一个权值。要求执行以下操作:
U V K:求从节点 \(u\oplus lastans\) 到节点 \(v\) 的第 \(k\) 小权值。
analysis
- 离散化,把节点的点权换成它在所有点权中的排名;
- 建立主席树,每个节点维护它到根的路径上的权值线段树,所以每个节点可以利用它的父节点更新,所以将整棵树 \(dfs\) 一遍,在此过程中建树。
- 求解:用 \(x\) 点的主席树 \(+y\) 点的主席树 \(-lca(x,y)\) 的主席树 \(-lca(x,y)\) 父节点的主席树,在这样产生的主席树上查找第 \(k\) 小的排名,最后输出它原来的点权。
code
#include<bits/stdc++.h>
const int maxn=1e5+10;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
int ver[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
namespace SGT
{
struct Orz{int l,r,z;}c[maxn*30];
int num=0;
inline void insert(int y,int &x,int l,int r,int p)
{
c[x=++num]=c[y];
++c[x].z;
if (l==r) return ;
int mid=(l+r)>>1;
if (p<=mid) insert(c[y].l,c[x].l,l,mid,p);
else insert(c[y].r,c[x].r,mid+1,r,p);
c[x].z=c[c[x].l].z+c[c[x].r].z;
}
inline int query(int x,int y,int z,int d,int l,int r,int k)
{
if (l==r) return l;
int res=c[c[x].l].z+c[c[y].l].z-c[c[z].l].z-c[c[d].l].z;
int mid=(l+r)>>1;
if (k<=res) return query(c[x].l,c[y].l,c[z].l,c[d].l,l,mid,k);
else return query(c[x].r,c[y].r,c[z].r,c[d].r,mid+1,r,k-res);
}
}
using SGT::insert;
using SGT::query;
int val[maxn],rt[maxn], n,m,tot;
namespace lca
{
int dep[maxn],f[maxn][21];
inline void dfs(int x)
{
insert(rt[f[x][0]],rt[x],1,tot,val[x]);
for (int i=1; i<=20; ++i) f[x][i]=f[f[x][i-1]][i-1];
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (y==f[x][0]) continue;
f[y][0]=x;
dep[y]=dep[x]+1;
dfs(y);
}
}
inline int LCA(int x,int y)
{
if (dep[x]>dep[y]) std::swap(x,y);
for (int i=20; i>=0; --i)
if (dep[y]-(1<<i)>=dep[x]) y=f[y][i];
if (x==y) return x;
for (int i=20; i>=0; --i)
if (f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
}
using namespace lca;
int a[maxn];
int main()
{
read(n);read(m);
for (int i=1; i<=n; ++i) read(val[i]),a[i]=val[i];
for (int i=1,x,y; i<n; ++i) read(x),read(y),add(x,y),add(y,x);
std::sort(a+1,a+n+1);
tot=std::unique(a+1,a+n+1)-a-1;
for (int i=1; i<=n; ++i) val[i]=std::upper_bound(a+1,a+tot+1,val[i])-a-1;
dfs(1);
int ans=0;
for (int i=1; i<=m; ++i)
{
int x,y,k;
read(x);read(y);read(k);
x^=ans;
int z=LCA(x,y);
write(ans=a[ query(rt[x],rt[y],rt[z],rt[f[z][0]],1,tot,k) ],'\n');
}
IO::flush();
return 0;
}