题意:n个结点形成一棵树,每个结点有一个权值,两种操作:一、改变某个结点的权值。二、查询结点u到结点v的路径上第k大的权值。
由于牵涉修改操作,因此不便用离线tarjan来做,这里采用LCA转RMQ的方法来求LCA。
建树之后DFS求出各个结点的深度dep、欧拉序列E、第一次在欧拉序列中出现的位置pos、以及前驱结点pre。
然后可转化为RMQ来查询两个结点的路径中深度最小的结点在欧拉序列中的下标,该结点就是这两个结点的最近公共祖先(LCA)。
得到LCA之后,通过前驱结点得到两个结点路径上经过的所有结点,然后排序,得到第k大的结点。
注意,RMQ查询的是欧拉序列的下标!!欧拉序列大小为2*n-1,初始化RMQ的时候,不要误将n作为欧拉序列大小。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;
#define maxn 80001
struct Edge{
int to,next,w;
}edge[maxn<<1];
int a[maxn],head[maxn],stk[maxn<<1],pre[maxn],dep[maxn<<1],cnt,pos[maxn],E[maxn<<1],dfn,f[maxn<<1][20];
inline void add(int u,int v)
{
edge[cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
memset(pos,-1,sizeof(pos));
memset(pre,-1,sizeof(pre));
cnt=dfn=0;
}
void dfs(int u,int deep)
{
if(pos[u]!=-1) return;
E[dfn]=u,dep[dfn]=deep,pos[u]=dfn++;
for(int i=head[u];~i;i=edge[i].next)
{
int v=edge[i].to;
if(pos[v]==-1)
{
pre[v]=u;
dfs(v,deep+1);
E[dfn]=u,dep[dfn++]=deep;
}
}
}
void init_RMQ(int n)
{
for(int i=1;i<=n;++i) f[i][0]=i;
for(int j=1;(1<<j)<=n;++j)
for(int i=1;i+(1<<j)-1<=n;++i)
{
if(dep[f[i][j-1]]<dep[f[i+(1<<(j-1))][j-1]]) f[i][j]=f[i][j-1];
else f[i][j]=f[i+(1<<(j-1))][j-1];
}
}
inline int RMQ(int L,int R)
{
int k=0;
while(1<<(k+1)<=R-L+1) ++k;
if(dep[f[L][k]]<dep[f[R-(1<<k)+1][k]]) return f[L][k];
return f[R-(1<<k)+1][k];
}
inline int lca(int u,int v)
{
if(pos[u]>pos[v]) return E[RMQ(pos[v],pos[u])];
return E[RMQ(pos[u],pos[v])];
}
bool cmp(int x,int y) {return x>y;}
void Find(int k,int u,int v)
{
int fa=lca(u,v),tot=0;
while(u!=fa){
stk[tot++]=a[u];
u=pre[u];
}
while(v!=fa){
stk[tot++]=a[v];
v=pre[v];
}
stk[tot++]=a[fa];
if(tot<k) puts("invalid request!");
else{
sort(stk,stk+tot,cmp);
printf("%d\n",stk[k-1]);
}
}
int main()
{
int n,i,u,v,k,q;
while(~scanf("%d%d",&n,&q))
{
for(i=1;i<=n;++i) scanf("%d",&a[i]);
init();
for(i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
pre[1]=1;
dfs(1,0);
init_RMQ(2*n-1);
while(q--)
{
scanf("%d%d%d",&k,&u,&v);
if(!k) a[u]=v;
else Find(k,u,v);
}
}
return 0;
}