题意:n个结点形成一棵树,每个结点有一个权值,两种操作:一、改变某个结点的权值。二、查询结点u到结点v的路径上第k大的权值。
由于牵涉修改操作,因此不便用离线tarjan来做,这里采用LCA转RMQ的方法来求LCA。
关于LCA与RMQ的相互转换
建树之后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; }