貌似求LCA使用倍增已经可以应付掉大多数需要LCA的题了..
但是有些时候$O(MlogN)$的复杂度就不可接受了
Tarjan_LCA对于每个询问采用离线处理
总复杂度为$O(M+N)$
这个复杂度几乎不可能被卡掉
简单说的话用Tarjan求LCA就是根据后序dfs的框架然后用并查集加持。
具体实现过程参加代码。
用HDU2586作为模板
//HUD 2586 Tarjan_LCA //by Cydiater //2016.8.15 #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cstdlib> #include <cmath> #include <ctime> #include <queue> #include <map> #include <iomanip> #include <algorithm> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) const int MAXN=1e6+5; const int oo=0x3f3f3f3f; inline int read(){ char ch=getchar();int x=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int N,M,LINK[MAXN],len=0,dis[MAXN],fa[MAXN],tol=0,Link[MAXN],g[MAXN],T,ans[MAXN]; bool vis[MAXN]; struct edge{int y,next,v;}e[MAXN]; struct query{int y,next,lca;}q[MAXN]; namespace solution{ inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;} inline void Insert(int x,int y){q[++tol].next=Link[x];Link[x]=tol;q[tol].y=y;} int get(int k){ if(g[k]==k) return k; g[k]=get(g[k]); return g[k]; } void dfs(int node,int dist,int father){ fa[node]=father;dis[node]=dist; for(int i=LINK[node];i;i=e[i].next) if(e[i].y!=father) dfs(e[i].y,dist+e[i].v,node); } void init(){ N=read();M=read(); up(i,1,N-1){ int x=read(),y=read(),v=read(); insert(x,y,v); insert(y,x,v); } memset(fa,0,sizeof(fa)); memset(dis,0,sizeof(dis)); memset(vis,0,sizeof(vis)); dfs(1,0,0); up(i,1,M){ int x=read(),y=read(); Insert(x,y); } } void lca(int node){ vis[node]=1;g[node]=node; for(int i=LINK[node];i;i=e[i].next) if(!vis[e[i].y]){ lca(e[i].y); g[e[i].y]=node; } for(int i=Link[node];i;i=q[i].next) if(vis[q[i].y]){ q[i].lca=get(q[i].y); ans[i]=dis[node]+dis[q[i].y]-2*dis[q[i].lca]; } } void output(){ up(i,1,M)printf("%d\n",ans[i]); } } int main(){ //freopen("input.in","r",stdin); using namespace solution; T=read(); while(T--){ tol=0;len=0; memset(Link,0,sizeof(Link)); memset(LINK,0,sizeof(LINK)); init(); lca(1); output(); } return 0; }