文章标题 HDU 2874 : Connections between cities(LCA+并查集)

来源:互联网 发布:淘宝买家怎么提升等级 编辑:程序博客网 时间:2024/06/08 14:21

题目链接
题意:有n个点组成的森林,然后有c个询问,每次询问u->v有没有一条路径,有的话,输出这条路径的距离,没有的话输出“Not connected”
分析:首先,判断是否有路径到达,只需要用并查集,看一下两个点是否在同一颗树上,然后对于有路径的两个点,我们可以求他们的LCA,然后通过dis[u]+dis[v]-2*dis[lca]来得到答案,但是题目给的是森林不是树,可以用另一个点作为树根,然后将森林中的每一颗树给连起来,这样就是一颗树了。
代码:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <queue>#include <set>#include <map>#include <algorithm>#include <math.h>#include <vector>using namespace std;typedef long long ll;const int mod=1e9+7;const int maxn=1e6+10;int n,m,c;int fa[maxn];//并查集 int find(int x){    return x==fa[x]?x:fa[x]=find(fa[x]); }//建图 struct Edge{    int to,nex,val;}edge[maxn];int head[maxn],tot;void init(){    tot=0;    memset (head,-1,sizeof (head));}void addedge(int u,int v,int w){    edge[tot]=Edge{v,head[u],w};    head[u]=tot++;} //lca.. int dis[maxn];//dis[i]表示节点i到树根的距离 int dp[maxn*2][20];int first[maxn];//first[i]表示i这个节点第一次出现的标号 int dep[maxn*2];//深度 int point[maxn*2];//point[i]表示标号为i所对应的节点 int vis[maxn];//标记节点是否被访问过了 int cnt;//遍历是节点的数目 void dfs(int u,int idx){//深搜     vis[u]=true;    point[++cnt]=u;    first[u]=cnt;    dep[cnt]=idx;    for (int i=head[u];i!=-1;i=edge[i].nex){        int v=edge[i].to;        int w=edge[i].val;        if (!vis[v]){            dis[v]=dis[u]+w;            dfs(v,idx+1);            point[++cnt]=u;            dep[cnt]=idx;        }     }}void RMQ_init(int n){//预处理     for (int i=1;i<=n;i++)dp[i][0]=i;    for (int k=1;(1<<k)<=n;k++){        for (int i=1;i+(1<<k)-1<=n;i++){            int a=dp[i][k-1];            int b=dp[i+(1<<(k-1))][k-1];            if (dep[a]>dep[b])dp[i][k]=b;            else dp[i][k]=a;        }    }} int RMQ(int l,int r){//求最小值     int k=0;    while ((1<<(k+1))<=r-l+1)k++;    int a=dp[l][k];    int b=dp[r-(1<<k)+1][k];    return dep[a]>dep[b]?b:a;}int LCA(int u,int v){//求LCA     int x=first[u],y=first[v];    if (x>y)swap(x,y);    int ans=RMQ(x,y);    return point[ans];}int main(){    while (scanf ("%d%d%d",&n,&m,&c)!=EOF){        int u,v,w;        init();        for (int i=0;i<=n;i++)fa[i]=i;        for (int i=0;i<m;i++){            scanf ("%d%d%d",&u,&v,&w);            int fu=find(u),fv=find(v);            if (fu!=fv){                fa[fu]=fv;            }             addedge(u,v,w);            addedge(v,u,w);        }        for (int i=1;i<=n;i++){//以n+1为树根,将森林连成树             if (fa[i]==i){                addedge(n+1,i,0);                addedge(i,n+1,0);            }        }         memset (dis,0,sizeof (dis));        memset (dep,0,sizeof (dep));        memset (vis,0,sizeof (vis));        cnt=1;        dfs(n+1,1);         RMQ_init(cnt-1);//初始化RMQ         while (c--){            scanf ("%d%d",&u,&v);            int fu=find(u),fv=find(v);            if (fu!=fv){                printf ("Not connected\n");            }             else {                int lca=LCA(u,v);                ll ans=dis[u]+dis[v]-2*dis[lca];                printf ("%lld\n",ans);            }        }     }     return 0;}
原创粉丝点击