题意:有n个点,n-1条双向边,每个点有一个值val,现在有q次询问(op,a,b),if(op==0)将a点的值改成b,否则,求a-->b 间所有点的第k大的值,包括a,b点。
解:
先求出a,b点的LCA,然后分别从a,b点询问到lca,记录下路径中所有的点,排序即可,修改操作直接修改。
由于tarjan是离线的算法,题中有修改操作,tarjan 不适合使用
//RMQ求LCA
#include<iostream>
#include<string>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<math.h>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
#define MAXN 40105*2
#define LL long long
#define INF 0x3f7f7f7f
const double eps = 1e-10;
int n,q;
int p[MAXN],num,tot;
int numd,deep[2*MAXN];//深度序列
int pos[2*MAXN];//点x第一次出现在欧拉序中的位置
int seq[2*MAXN];//欧拉序
int d[2*MAXN][20],f[MAXN];
//d[i][j]表示从i开始后面的2^j个元素(深度序列)最小的值的下标号
int val[MAXN],ans[MAXN];
struct edge
{
int en,next;
}E[MAXN*2];
void add(int st,int en)
{
E[num].en=en;
E[num].next=p[st];
p[st]=num++;
}
void init()
{
memset(p,-1,sizeof(p));
num=0;
numd=0;
}
void dfs(int x,int fa,int depth)
{
deep[++numd]=depth;
seq[numd]=x;
pos[x]=numd;
f[x]=fa;
for(int i=p[x];i!=-1;i=E[i].next)
{
int en=E[i].en;
if(en!=fa)
{
dfs(en,x,depth+1);
deep[++numd]=depth;
seq[numd]=x;
}
}
}
void initRmq()
{
int i,j;
for(i=1;i<=numd;i++)
{
d[i][0]=i;
}
for(j=1;(1<<j)<= numd;j++)
{
for(i=1;i<=numd-(1<<j)+1;i++)
{
if(deep[d[i][j-1]] < deep[d[i+(1<<(j-1))][j-1]])
d[i][j]=d[i][j-1];
else d[i][j]=d[i+(1<<(j-1))][j-1];
}
}
}
int query(int l,int r)
{
l=pos[l],r=pos[r];
if(l>r)
swap(l,r);
int k=0,temp;
while((1<<k) <= r-l+1)
k++;
k--;
if(deep[d[l][k]] < deep[d[r-(1<<k)+1][k]])
temp=d[l][k];
else temp=d[r-(1<<k)+1][k];
return seq[temp];
}
void findfa(int x,int lca)
{
if(x==lca)
{
return;
}
ans[++tot]=val[x];
findfa(f[x],lca);
}
bool cmp(int x,int y)
{
return x>y;
}
void solve(int u,int v,int lca,int x)
{
tot=0;
findfa(u,lca);
findfa(v,lca);
ans[++tot]=val[lca];
sort(ans+1,ans+1+tot,cmp);
if(x<=tot)
printf("%d\n",ans[x]);
else
puts("invalid request!");
}
int main()
{
int i,u,v;
scanf("%d%d",&n,&q);
init();
for(i=1;i<=n;i++)
{
scanf("%d",&val[i]);
}
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs(1,-1,0);//root,fa,depth
initRmq();
for(i=1;i<=q;i++)
{
int x;
scanf("%d%d%d",&x,&u,&v);
if(x==0)
{
val[u]=v;
}
else {
int ask=query(u,v);
solve(u,v,ask,x);
}
}
return 0;
}