这里有可能不连通,可以通过添加一个虚根把森林变成树,最后如果LCA(u,v) = 0就表示不连通
个人比较喜欢用离线算法,tarjan还需要掌握
#define N 10010 struct edge{ int v; int len; int next; }e[2*N]; int ecnt; int head[N]; bool vis[N]; int n;//点数 int R[N];//第一次出现i点下标 int p[N*2];//记录路径点编号 int dis[N];//与根的距离 int dep[2*N];//深度 int dp[20][2*N];//从j开始长度为2^i路径的最近公共祖先下标,这里这里!!!第二维要2倍大小!! int num; int fa[N]; void init(){ memset(head,-1,sizeof(head)); memset(R,-1,sizeof(R)); memset(vis,0,sizeof(vis)); for(int i=1;i<=n;i++)fa[i] = i; ecnt=0; } void add(int u,int v,int len){ e[ecnt].v = v; e[ecnt].len = len; e[ecnt].next = head[u]; head[u] = ecnt++; e[ecnt].v = u; e[ecnt].len = len; e[ecnt].next = head[v]; head[v] = ecnt++; } int find(int x){ if(fa[x] != x) fa[x] = find(fa[x]); return fa[x]; } void uni(int u,int v){ int a = find(u); int b = find(v); if(a == b)return ; fa[a] = b; } void dfs(int u,int depth){ vis[u] = 1; p[++num] = u; dep[num] = depth; for(int i=head[u];i!=-1;i=e[i].next){ int v = e[i].v; if(!vis[v]){ dis[v] = dis[u]+e[i].len; dfs(v,depth+1); p[++num] = u; dep[num] = depth; } } } void init_rmq(){ int i,j; for(i=1;i<=num;i++){ if(R[p[i]] == -1){ R[p[i]] = i; } } for(i=1;i<=num;i++){ dp[0][i] = i; } int t = (int)(log(num*1.0)/log(2.0)); for(i=1;i<=t;i++){ for(j=1;j+(1<<(i-1))<=num;j++){ int a = dp[i-1][j],b = dp[i-1][j+(1<<(i-1))]; if(dep[a]<=dep[b]){ dp[i][j] = a; } else dp[i][j] = b; } } } int rmq(int u,int v){//返回最近公共祖先的编号 if(R[u]>=R[v])swap(u,v); int s = R[u],t = R[v]; int k = (int)(log((t-s+1)*1.0)/log(2.0)); int a = dp[k][s],b = dp[k][t-(1<<k)+1]; if(dep[a]<=dep[b])return p[a]; else return p[b]; } int main(){ int m,c; while(scanf("%d%d%d",&n,&m,&c) != -1){ int i,j; init(); int x,y,z; while(m--){ scanf("%d%d%d",&x,&y,&z); add(x,y,z); uni(x,y); } for(i=1;i<=n;i++){ if(fa[i] == i){ add(i,0,0);//添加虚根0把森林变成树 } } num = 0; dis[0] = dep[0] = 0; dfs(0,0); init_rmq(); while(c--){ scanf("%d%d",&x,&y); int f = rmq(x,y); if(!f)puts("Not connected"); else printf("%d\n",dis[x]+dis[y]-2*dis[f]); } } return 0; }