时间复杂度O(n+mlogn)
vector<int>e[maxn];
int fa[maxn],dep[maxn],son[maxn],sz[maxn];
// 存u的父节点,存u的深度,存u的重儿子,存以u为根的子树的节点数
int top[maxn];
// 存u所在重链的顶点
void dfs1(int u,int father){fa[u]=father,dep[u]=dep[father]+1,sz[u]=1;for(int v:e[u]){if(v==father)continue;dfs1(v,u);sz[u]+=sz[v];if(sz[son[u]]<sz[v]){son[u]=v;}}
}
void dfs2(int u,int t){top[u]=t;if(!son[u])return;//遇到叶子节点返回 dfs2(son[u],t);//向下搜重儿子for(int v:e[u]){if(v==fa[u]||v==son[u])continue;dfs2(v,v);//搜轻儿子 }
}
int lca(int u,int v){while(top[u]!=top[v]){if(dep[top[u]]<dep[top[v]])swap(u,v);u=fa[top[u]];}return dep[u]<dep[v]?u:v;
}