zoukankan      html  css  js  c++  java
  • Codeforces Gym 100015C City Driving 离线LCA

    City Driving

    题目连接:

    http://codeforces.com/gym/100015/attachments

    Description

    You recently started frequenting San Francisco in your free time and realized that driving in the city is a
    huge pain. There are only N locations in the city that interest you, though, and you have decidedtotry
    to improve your driving experience. Since you lack a GPS and cannot remember too many di!erent routes,
    you wrote down the directions and how long it takes to get between N di!erent pairs of locations (the same
    in both directions), ensuring that using only these paths you can get from any location to any other one.
    Now you are planning your trip for the weekend and you need to figureoutthefastestwaytogetbetween
    Q pairs of locations in the city using only the routes you have written down.

    Input

    The input consists of multiple test cases. The first line contains a single integer N,3 ! N ! 100,000, the
    number of locations of interest and the number of routes you wrotedown.Thenext N lines each contain
    three integers u, v,and w (1 ! w ! 1,000), indicating that you have directions from location u to location v
    and vice-versa (0-indexed) which take w time. The following line contains a single integer Q,1 ! Q ! 10,000,
    the number of pairs of locations you need to compute the travel timefor. Thenext Q lines each contain
    two integers u and v, indicating that you should find the minimum time to get from location u to location
    v. The input terminates with a line with N = 0. For example:

    Output

    For each test case, print out Q lines, one for each pair of locations u and v you are finding the fastest routes
    for. Each line should simply contain the minimum time it takes to travel from location u to location v.For
    example, the correct output for the sample input above would be:

    Sample Input

    7

    0 1 2

    0 2 3

    1 3 2

    2 3 8

    2 4 3

    3 5 1

    1 6 7

    3

    4 5

    0 6

    1 2

    0

    Sample Output

    11

    9

    5

    Hint

    题意

    给你一个n环n边的图,问你两点之间的最短路

    题解:

    随便找一个环,然后在这个环上随便去掉一条边,然后就比较这个树上的距离小,还是经过这条边的饿距离小

    比如你去掉的边是a,b,边权是w,你查询u,v

    那么你比较dis(u,v),dis(u,a)+w+dis(b,v),dis(u,b)+w+dis(a,u)就好了

    找环上的边,我推荐用并查集

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 100005
    struct node
    {
        int x,y;
    };
    vector<node>G[maxn];
    int dp[18][maxn*2],dis[maxn],parent[maxn],vis[maxn],pos[maxn],res[maxn];
    int n,m,c,num,cnt,si;
    int qx=0,qy=0,qv=0;
    void init()
    {
        qx = qy = qv = 0;
        cnt = num = si = 0;
        memset(dp,0,sizeof(dp));
        memset(dis,0,sizeof(dis));
        memset(vis,0,sizeof(vis));
        memset(res,0,sizeof(res));
        memset(pos,0,sizeof(pos));
        for(int i=0;i<maxn;i++)
            G[i].clear();
    }
    int Find(int i)
    {
        if(i!=parent[i])
            parent[i]=Find(parent[i]);
        return parent[i];
    }
    void Union(int i,int j)
    {
        int x,y;
        x=Find(i);
        y=Find(j);
        if(x!=y)
            parent[x]=y;
    }
    
    void dfs3(int u,int dist)
    {
        int i,j;
        vis[u]=1;
        dis[u]=dist;
        pos[u]=cnt;
        res[si]=u;
        dp[0][cnt++]=si++;
        for(i=0;i<G[u].size();i++)
        {
            j=G[u][i].x;
            if(!vis[j])
            {
                dfs3(j,dist+G[u][i].y);
                dp[0][cnt++]=dp[0][pos[u]];
            }
        }
    }
    void rmq()
    {
        int i,j,k;
        for(i=1;(1<<i)<=n;i++)
            for(j=n-1;j>=0;j--)
            {
                k=(1<<(i-1));
                dp[i][j]=dp[i-1][j];
                if(k+j<n)
                    dp[i][j]=min(dp[i][j],dp[i-1][j+k]);
            }
    }
    int cal(int i,int j)
    {
        int k;
        if(i<j)swap(i,j);
        k=0;
        while((1<<k)<=(i-j+1))
            k++;
        k--;
        k=min(dp[k][j],dp[k][i-(1<<k)+1]);
        return res[k];
    }
    int Dis(int u,int v)
    {
        int k = cal(pos[u],pos[v]);
        return dis[u]+dis[v]-dis[k]*2;
    }
    int main()
    {
        while(scanf("%d",&n)!=EOF)
        {
            if(n==0)break;
            init();
            for(int i=0;i<=n;i++)
                parent[i]=i;
            for(int i=1;i<=n;i++)
            {
                int x,y,z;scanf("%d%d%d",&x,&y,&z);
                x++,y++;
                int p = Find(x),q = Find(y);
                if(p==q){
                    qx = x,qy = y,qv = z;
                    continue;
                }
                Union(x,y);
                G[x].push_back((node){y,z});
                G[y].push_back((node){x,z});
            }
            for(int i=1;i<=n;i++)
                if(!vis[i])
                    dfs3(i,0);
            n=n*2-1;
            rmq();
            int q;
            scanf("%d",&q);
            while(q--)
            {
                int x,y;scanf("%d%d",&x,&y);
                x++,y++;
                int res = Dis(x,y);
                res = min(res,Dis(x,qx)+Dis(y,qy)+qv);
                res = min(res,Dis(x,qy)+Dis(y,qx)+qv);
                printf("%d
    ",res);
            }
        }
    }
  • 相关阅读:
    Hibernate缓存机制
    如何建立索引
    数据库索引及基本优化入门
    索引优化-2
    索引优化-1
    Linux基本命令参数
    Spring 依赖注入(控制反转)介绍
    Linux的软连接和硬连接
    聚簇索引(Clustered Index)和非聚簇索引 (Non- Clustered Index)
    常见和链表相关的算法
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5136261.html
Copyright © 2011-2022 走看看