链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874
题意:给你一个不完整的树,让你判断任意两点的情况,不联通或者最小距离。
总结:这道题因为数据原因,不能用最短路的算法写。而是LCA,算是一道LCA入门题。
思路:利用LCA+ST求解,如果两个点没有边就加一个无限大的边(用到了并查集),然后构造要RMQ的数组,ST求解一套带走。
ps:我用了指针链表建图,每次应该收回内存的,这项工作还没做。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
using namespace std;
const int inf = 999999999;
const int N = 100000+10;
struct edge
{
int to,value;
edge *next;
};
struct node
{
edge *next;
};
node dian[N];
int fa[N],du[N>>1],len[N],f[N][25],first[N],book[N],tail;
int Findfa(int n);
void union_xy(int x,int y);
void dfs(int rt, int dis);
void addEdge(int a,int b,int c);
void makeRMQ(int n);
int Anwer(int s,int v);
void chushihua(int n)
{
for(int i=1; i<=n; i++)
fa[i] = i,dian[i].next = NULL;
memset(du,0,sizeof(du));
memset(book,0,sizeof(book));
memset(len,0,sizeof(len));
}
int main()
{
int n,m,c,i;
while(~scanf("%d%d%d",&n,&m,&c))
{
int a,b,v;
chushihua(n);
while(m--)
{
scanf("%d%d%d",&a,&b,&v);
addEdge(a,b,v);
addEdge(b,a,v);
union_xy(a,b);//并查集
}
for(i=2; i<=n; i++)
if(fa[i] == i) //将没有和点1的节点加入图
{
addEdge(1,i,inf);
union_xy(1,i);
}
tail = 0;
dfs(1,0);
makeRMQ(tail);//构造du数组 , 就是我要RMQ的那个数组
while(c--)
{
scanf("%d%d",&a,&b);
int ans = Anwer(first[a],first[b]);
if(len[a]+len[b] - 2*ans >= inf)
printf("Not connected\n");
else
printf("%d\n",len[a]+len[b]-2*ans);
}
}
return 0;
}
int Findfa(int n)
{
if(fa[n] == n)
return n;
return fa[n] = Findfa(fa[n]);
}
void union_xy(int x,int y)
{
int ax = Findfa(x);
int ay = Findfa(y);
if(ax != ay)//让节点1做头节点
{
if(ax == 1)
fa[ay] = ax;
else
fa[ax] = ay;
}
}
void addEdge(int a,int b,int c)
{
edge *l = new edge;
l->to = b;
l->value = c;
l->next = dian[a].next;
dian[a].next = l;
}
void dfs(int rt, int dis)
{
if(book[rt] == 0)
{
book[rt] = 1;
first[rt] = ++tail;
du[tail] = rt;
len[rt] = dis;
}
edge *l = dian[rt].next;
while(l)
{
if(book[l->to] == 0)
{
dfs(l->to,dis+l->value);
du[++tail] = rt;
}
l = l->next;
}
}
void makeRMQ(int n)
{
int i,j;
for(i=1; i<=n; i++)
f[i][0] = len[du[i]];
for(j=1; (1<<j) <=n; j++)
for(i=1; i+(1<<j)<=n; i++)
{
f[i][j] = min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
}
int Anwer(int s,int v)
{
if(s > v)
{
int t = s;
s = v;
v = t;
}
int m = log2(v-s+1);
return min(f[s][m],f[v-(1<<m)+1][m]);
}