HDU 2874 Connections between cities

链接: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]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值