Problem Address:http://acm.hdu.edu.cn/showproblem.php?pid=2874
【前言】
这两天在做LCA的问题。
昨天做了一道模板题,今天再做一道。
但是一开始就被C++WA而G++AC困惑着。
最后的最后,好久好久以后,终于得到了一个结论。
【思路】
题意所给是一个森林,那么加多一个虚根节点,使其成为一棵树。
如果两个节点的LCA是虚根节点,则表示不可连通。
否则距离等于每个节点到虚根节点的距离之和减去两倍LCA到虚根节点的距离。
可以使用并查集,但是貌似跟直接深搜的时间差不多。不过可能会好一点。
【代码】
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
const int maxn = 10000;
struct node
{
int length;
int index;
int next;
node(int idx = 0, int len = 0)
{
index = idx;
length = len;
}
}edge[maxn<<1+5];
int head[maxn+5];
int ect;
void addedge(int from, int to, int len)
{
edge[ect].index = to;
edge[ect].length = len;
edge[ect].next = head[from];
head[from] = ect;
ect++;
}
int F[maxn<<1];
int B[maxn<<1];
int Pos[maxn+5];
int D[maxn+5];
int has[maxn+5];
void dfs(int rt, int level, int len, int &ct)
{
ct++;
has[rt] = 1;
F[ct] = rt;
B[ct] = level;
D[rt] = len;
Pos[rt] = ct;
int i;
for (i=head[rt]; i+1!=0; i=edge[i].next)
{
if (has[edge[i].index]==0)
{
dfs(edge[i].index, level+1, len+edge[i].length, ct);
ct++;
F[ct] = rt;
B[ct] = level;
}
}
}
int dpmin[maxn<<1+10][20];
void ST(int n)
{
int i,j;
for (i=1; i<=n; i++)
{
dpmin[i][0] = i;
}
int m = (int)floor(log((double)n)/log(2.0));
for (j=1; j<=m; j++)
{
for (i=1; i<=n; i++)
{
dpmin[i][j] = dpmin[i][j-1];
if (i+(1<<(j-1))<=n)
{
if (B[dpmin[i][j-1]]<B[dpmin[i+(1<<(j-1))][j-1]])
dpmin[i][j] = dpmin[i][j-1];
else
dpmin[i][j] = dpmin[i+(1<<(j-1))][j-1];
}
}
}
}
int st_getmin(int l, int r)
{
int k = floor(log((double)(r-l+1))/log(2.0));
if (B[dpmin[l][k]]<B[dpmin[r-(1<<k)+1][k]])
return dpmin[l][k];
else
return dpmin[r-(1<<k)+1][k];
}
int getmin(int a, int b)
{
a = Pos[a], b = Pos[b];
if (a>b) swap(a, b);
return F[st_getmin(a, b)];
}
void solve(int rt)
{
int ct = 0;
memset(has, 0, sizeof(has));
dfs(rt, 0, 0, ct);
ST(ct);
}
int father[maxn+5];
void init(int n)
{
int i;
for (i=0; i<=n; i++)
{
father[i] = i;
}
}
inline int getroot(int x)
{
int r = x;
while(father[r]!=r)
{
r = father[r];
}
while(father[x]!=r)
{
father[x] = r;
x = father[x];
}
return r;
}
inline void join(int s, int x)
{
int a = getroot(s);
int b = getroot(x);
if (a!=b)
{
father[a] = b;
}
}
int main()
{
int n, m, c;
int x, y, z;
int i;
while(scanf("%d %d %d", &n, &m, &c)!=EOF)
{
for (i=1; i<=n+1; i++) head[i] = -1;
ect = 0;
//以下所有注释部分就是使用并查集
// init(n+1);
for (i=0; i<m; i++)
{
scanf("%d %d %d", &x, &y, &z);
addedge(x, y, z);
addedge(y, x, z);
// join(x, y);
}
memset(has, 0, sizeof(has));//这部分是使用深搜
for (i=1; i<=n; i++)
{
if (has[i]==0)
{
addedge(n+1, i, 0);
z = 0;//如果不赋值为0,g++AC,c++WA。
dfs(i, 0, 0, z);
}
}
/*
for (i=1; i<=n; i++)
if (father[i]==i)
addedge(n+1, i, 0);*/
solve(n+1);
while(c--)
{
scanf("%d %d", &x, &y);
int rt = getmin(x, y);
if (rt==n+1)
printf("Not connected\n");
else
printf("%d\n", D[x]+D[y]-2*D[rt]);
}
}
return 0;
}