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; }