传送门
写在前面:一天下来就写了两道主席树的题……(codevs上的一道智障天梯不算)
思路:
才知道原来主席树不仅可以通过dfs序维护子树区间,还可以直接维护一条到根的链……
我们建好主席树后,每次查询u->v路径上的第k大,无非有两种情况
1.u,v在同一条链上
2.u,v不在同一条链上
其实这两种情况处理起来是一样的,我们利用主席树中的前缀和思路,root[u]并上root[v]再减去root[lca(u,v)]再减去root[fa[lca(u,v)]]就是u->v路径上的点了(可以自己画图感受一下)
所以每次查询时要算四棵树之间的siz关系
注意:
1.求lca我用的是ST表,当然倍增也是可以的
2.最后一个答案不要换行!
代码:
#include<bits/stdc++.h>
#define M 100004
#define ls(x) a[x].ch[0]
#define rs(x) a[x].ch[1]
using namespace std;
int n,m,lastans,tot,maxn,cnt;
int fa[M],w[M],ID[M],first[M],dep[M],ST[M<<1][20],pos[M],num[M<<1];
struct disc
{
int data,id;
bool operator <(const disc other)const
{
return data<other.data;
}
}d[M];
struct edge
{
int u,v,next;
}e[M<<1];
struct Chairman_tree
{
int siz,ch[2];
}a[M*20];
int in()
{
char ch=getchar();int t=0;
while (!isdigit(ch))ch=getchar();
while (isdigit(ch)) t=(t<<3)+(t<<1)+ch-48,ch=getchar();
return t;
}
void add(int x,int y)
{
e[++tot]=(edge){x,y,first[x]};first[x]=tot;
e[++tot]=(edge){y,x,first[y]};first[y]=tot;
}
void build(int now,int L,int R,int rt,int val)
{
a[rt].siz=a[now].siz+1;
if (L==R) return;
int mid=(L+R)>>1;
if (mid>=val)
rs(rt)=rs(now),
ls(rt)=++cnt,
build(ls(now),L,mid,ls(rt),val);
else
a[rt].ch[0]=a[now].ch[0],
a[rt].ch[1]=++cnt,
build(rs(now),mid+1,R,rs(rt),val);
}
void dfs(int x)
{
num[++num[0]]=x;
pos[x]=num[0];
ST[num[0]][0]=x;
if (x==1) build(1,1,maxn,2,w[x]);
for (int i=first[x];i;i=e[i].next)
if (!pos[e[i].v])
{
dep[e[i].v]=dep[x]+1;
fa[e[i].v]=x;
build(x+1,1,maxn,e[i].v+1,w[e[i].v]);
dfs(e[i].v);
num[++num[0]]=x;
ST[num[0]][0]=x;
}
}
void init()
{
int x,y;
for (int i=1;i<=log2(num[0]);i++)
for (int j=1;j<=num[0]-(1<<i)+1;j++)
x=ST[j][i-1],y=ST[j+(1<<i-1)][i-1],
ST[j][i]=(dep[x]>dep[y]?y:x);
}
int LCA(int x,int y)
{
if (pos[x]>pos[y]) swap(x,y);
int p=pos[x],q=pos[y],t=log2(q-p+1);
if (dep[ST[p][t]]>dep[ST[q-(1<<t)+1][t]]) return ST[q-(1<<t)+1][t];
else return ST[p][t];
}
int get(int begin,int end,int u,int v,int lca,int fa,int k)
{
if (begin==end) return end;
int mid=(begin+end)>>1;
int t=a[ls(u)].siz+a[ls(v)].siz-
a[ls(lca)].siz-a[ls(fa)].siz;
if (k>t)
return get(mid+1,end,rs(u),rs(v),rs(lca),rs(fa),k-t);
else
return get(begin,mid,ls(u),ls(v),ls(lca),ls(fa),k);
}
main()
{
n=in();m=in();
for (int i=1;i<=n;i++)
w[i]=in(),
d[i].id=i,d[i].data=w[i];
sort(d+1,d+n+1);
maxn=1;
ID[1]=d[1].data;w[d[1].id]=1;
for (int i=2;i<=n;i++)
{
if (d[i].data!=d[i-1].data) maxn++,ID[maxn]=d[i].data;
w[d[i].id]=maxn;
}
for (int i=1;i<n;i++)
add(in(),in());
cnt=n+1;
dfs(1);
init();
int x,y,z,k;
while (m--)
{
x=in()^lastans;
y=in();k=in();
z=LCA(x,y);
lastans=ID[get(1,maxn,x+1,y+1,z+1,fa[z]+1,k)];
printf("%d",lastans);
if (m) putchar('\n');
}
}