HDU 2874 Connections between cities(LCA + RMQ)

Connections between cities

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7295    Accepted Submission(s): 1856


Problem Description
After World War X, a lot of cities have been seriously damaged, and we need to rebuild those cities. However, some materials needed can only be produced in certain places. So we need to transport these materials from city to city. For most of roads had been totally destroyed during the war, there might be no path between two cities, no circle exists as well.
Now, your task comes. After giving you the condition of the roads, we want to know if there exists a path between any two cities. If the answer is yes, output the shortest path between them.
 

Input
Input consists of multiple problem instances.For each instance, first line contains three integers n, m and c, 2<=n<=10000, 0<=m<10000, 1<=c<=1000000. n represents the number of cities numbered from 1 to n. Following m lines, each line has three integers i, j and k, represent a road between city i and city j, with length k. Last c lines, two integers i, j each line, indicates a query of city i and city j.
 

Output
For each problem instance, one line for each query. If no path between two cities, output “Not connected”, otherwise output the length of the shortest path between them.
 

Sample Input
5 3 2 1 3 2 2 4 3 5 2 3 1 4 4 5
 

Sample Output
Not connected

6

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <vector>
#include <algorithm>
#define ll long long 
using namespace std;
const int MAXN = 100000 + 10;
struct Edge{int to, next, w;}edge[MAXN<<1];
int read()
{
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') f *= -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0'; ch = getchar();}
    return x * f;
}
int tot, head[MAXN];
void init(){tot = 0, memset(head, -1, sizeof(head));}
void addedge(int u, int v, int w)
{edge[tot].to = v, edge[tot].w = w, edge[tot].next = head[u], head[u] = tot++;}
int n, m, q, u, v, w, dfs_clock;
int f[MAXN];
int find(int x){return f[x] == x ? x : f[x] = find(f[x]);}
int bin[35], id[MAXN], pos[MAXN], fa[MAXN][35],dis[MAXN], dep[MAXN];
int rmq[MAXN << 1];//建立RMQ的數組

//***************************
//ST算法,裏面含有初始化init(n)和query(s,t)函數
//點的編號從1開始,1-n.返回最小值的下標
//***************************
struct ST
{
    int mm[2*MAXN];//mm[i]表示i的最高位,mm[1]=0,mm[2]=1,mm[3]=1,mm[4]=2
    int dp[MAXN*2][20];
    void init(int n)
    {
        mm[0]=-1;
        for(int i=1;i<=n;i++)
        {
            mm[i]=((i&(i-1))==0?mm[i-1]+1:mm[i-1]);
            dp[i][0]=i;
        }
        for(int j=1;j<=mm[n];j++)
          for(int i=1;i+(1<<j)-1<=n;i++)
             dp[i][j]=rmq[dp[i][j-1]]<rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1];
    }
    int query(int a,int b)//查詢a到b間最小值的下標
    {
        if(a>b)swap(a,b);
        int k=mm[b-a+1];
        return rmq[dp[a][k]]<rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k];
    }
};

//邊的結構體定義
struct Node
{
    int to,next;
};

/* ******************************************
LCA轉化爲RMQ的問題
MAXN爲最大結點數。ST的數組 和 F,edge要設置爲2*MAXN

F是歐拉序列,rmq是深度序列,P是某點在F中第一次出現的下標
*********************************************/

struct LCA2RMQ
{
    int n;//結點個數
    Node edge[2*MAXN];//樹的邊,因爲是建無向邊,所以是兩倍
    int tol;//邊的計數
    int head[MAXN];//頭結點

    bool vis[MAXN];//訪問標記
    int F[2*MAXN];//F是歐拉序列,就是DFS遍歷的順序
    int P[MAXN];//某點在F中第一次出現的位置
    int cnt;

    ST st;
    void init(int n)//n爲所以點的總個數,可以從0開始,也可以從1開始
    {
        this->n=n;
        tol=0;
        memset(head,-1,sizeof(head));
    }
    void addedge(int a,int b)//加邊
    {
        edge[tol].to=b;
        edge[tol].next=head[a];
        head[a]=tol++;
        edge[tol].to=a;
        edge[tol].next=head[b];
        head[b]=tol++;
    }

    int query(int a,int b)//傳入兩個節點,返回他們的LCA編號
    {
        return F[st.query(P[a],P[b])];
    }

    void dfs(int a,int lev)
    {
        vis[a]=true;
        ++cnt;//先加,保證F序列和rmq序列從1開始
        F[cnt]=a;//歐拉序列,編號從1開始,共2*n-1個元素
        rmq[cnt]=lev;//rmq數組是深度序列
        P[a]=cnt;
        for(int i=head[a];i!=-1;i=edge[i].next)
        {
            int v=edge[i].to;
            if(vis[v])continue;
            dfs(v,lev+1);
            ++cnt;
            F[cnt]=a;
            rmq[cnt]=lev;
        }
    }

    void solve(int root)
    {
        memset(vis,false,sizeof(vis));
        cnt=0;
        dfs(root,0);
        st.init(2*n-1);
    }
}lca;
void dfs(int x, int pre)
{
    for(int i=head[x];i!=-1;i=edge[i].next)
    {
        if(edge[i].to != pre)
        {
            dis[edge[i].to] = dis[x] + edge[i].w;
            dfs(edge[i].to, x);
        }
    }
}
int main()
{
    while(scanf("%d%d%d", &n, &m, &q)!=EOF)
    {
        init();for(int i=0;i<=n;i++) f[i] = i;
        lca.init(n + 1);
        for(int i=1;i<=m;i++)
        {
            u = read(), v = read(), w = read();
            addedge(u, v, w); addedge(v, u, w);
            lca.addedge(u, v); lca.addedge(v, u);
            int x = find(u), y = find(v);
            if(x != y) f[x] = f[y];
        }
        int root = 0;
        for(int i=1;i<=n;i++) if(f[i] == i)
        {
            lca.addedge(root, i);
            lca.addedge(i, root);
            addedge(root, i, 0);
            addedge(i, root, 0);
        }
        dfs(root, -1);
        lca.solve(root);
        while(q--)
        {
            u = read(), v = read();
            int x = find(u), y = find(v);
            if(u == v) printf("0\n");
            else if(x != y) puts("Not connected");
            else
            {
                int x = lca.query(u, v);
                int ans = dis[u] - dis[x] + dis[v] - dis[x];
                printf("%d\n", ans);
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章