https://www.luogu.org/problem/P2633
题目描述
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor ans和v这两个节点间第K小的点权。其中ans是上一个询问的答案,初始为0,即第一个询问的u是明文。
思路:看到第k小就想到用主席树来做,关键是现在是求树链的第k小 ,怎么建主席树是一个问题。我们考虑在dfs的过程中建主席树,使节点u的树保存的是从根节点到u节点的信息,那么查询u到v路径的第k小需要用到四个点: u 、 v 、 L c a ( u , v ) 、 f a t h e r [ L c a ( u , v ) ] u、v、Lca(u,v)、father[Lca(u,v)] u、v、Lca(u,v)、father[Lca(u,v)]假设 g r a n d = L c a ( u , v ) , f g r a n d = f a t h e r [ L c a ( u , v ) ] grand=Lca(u,v),fgrand=father[Lca(u,v)] grand=Lca(u,v),fgrand=father[Lca(u,v)]那么令 d i s = s u m [ l c [ u ] ] + s u m [ l c [ v ] ] − s u m [ l c [ g r a n d ] ] − s u m [ l c [ f g r a n d ] ] dis=sum[lc[u]]+sum[lc[v]]-sum[lc[grand]]-sum[lc[fgrand]] dis=sum[lc[u]]+sum[lc[v]]−sum[lc[grand]]−sum[lc[fgrand]]拿dis与k比较即可。(和一般的主席树查询操作一样)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
int n,nn,m,tot=0,cnt=0;
int rt[maxn],a[maxn],b[maxn],head[maxn];
int deep[maxn];
int fa[maxn][30];
int bs[30];
struct node
{
int ls,rs,sum;
}tree[maxn*40];
struct edge
{
int to,nxt;
}Edge[maxn<<1];
inline void addedge(int u,int v)
{
Edge[++cnt].to=v,Edge[cnt].nxt=head[u],head[u]=cnt;
Edge[++cnt].to=u,Edge[cnt].nxt=head[v],head[v]=cnt;
}
void insert(int &x,int y,int l,int r,int pos)
{
tree[++tot]=tree[y];
x=tot;
++tree[x].sum;
if(l==r)
return;
int mid=(l+r)>>1;
if(pos<=mid)
insert(tree[x].ls,tree[y].ls,l,mid,pos);
else
insert(tree[x].rs,tree[y].rs,mid+1,r,pos);
}
int query(int u,int v,int grand,int fgrand,int l,int r,int k)
{
if(l==r)
return l;
int dis=tree[tree[u].ls].sum+tree[tree[v].ls].sum-tree[tree[grand].ls].sum-tree[tree[fgrand].ls].sum;
int mid=(l+r)>>1;
if(k<=dis)
return query(tree[u].ls,tree[v].ls,tree[grand].ls,tree[fgrand].ls,l,mid,k);
else
return query(tree[u].rs,tree[v].rs,tree[grand].rs,tree[fgrand].rs,mid+1,r,k-dis);
}
void dfs(int cur,int father)
{
insert(rt[cur],rt[father],1,nn,a[cur]);
deep[cur]=deep[father]+1;
fa[cur][0]=father;
for(int i=1;i<=20;i++)
fa[cur][i]=fa[fa[cur][i-1]][i-1];
for(int i=head[cur];i;i=Edge[i].nxt)
if(Edge[i].to!=father)
dfs(Edge[i].to,cur);
}
inline int skip(int x,int level)
{
for(int i=20;i>=0;i--)
{
if(bs[i]&level)
x=fa[x][i];
}
return x;
}
inline int LCA(int u,int v)
{
if(deep[u]<deep[v])
swap(u,v);
u=skip(u,deep[u]-deep[v]);
if(u==v)
return u;
for(int i=20;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=0;i<=20;i++)
bs[i]=1<<i;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+1,b+1+n);
nn=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+nn,a[i])-b;
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
addedge(u,v);
}
dfs(1,0);
}
inline void mainwork()
{
int u,v,k,ans=0,tmp,grand;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&u,&v,&k);
u^=ans;
grand=LCA(u,v);
tmp=b[query(rt[u],rt[v],rt[grand],rt[fa[grand][0]],1,nn,k)];
printf("%d\n",tmp);
ans=tmp;
}
}
int main()
{
prework();
mainwork();
return 0;
}