[Codeforces 1051F] The Shortest Statement

[题目链接]

         https://codeforces.com/contest/1051/problem/F

[算法]

        注意边数 - 点数 <= 20 , 我们不妨首先求出图的任意一棵生成树 , 不在生成树内的边最多有21条 , 这些边不同的端点最多有42个

        对这些点分别运行Dijkstra最短路

        回答“u至v的最短路"时 , 有如下两种情况 :

        1. 全部在生成树的边上 , 答案为生成树上两点距离

        2. 经过非树边 , 这样 , 我们只需枚举所有不在生成树内的边的端点 , 用其到u的最短路径 + 到v的最短路径更新答案即可

        时间复杂度 : O(NlogN)

[代码]

         

#include
using namespace std;
#define MAXK 50
#define MAXLOG 20
const int MAXN = 1e5 + 10;
const long long inf = 1e18;

int tot , n , m , q , k;
int head[MAXN],f[MAXN],depth[MAXN],u[MAXN],v[MAXN],w[MAXN];
int anc[MAXN][MAXLOG];
bool mark[MAXN];
long long ans[MAXN],sum[MAXN];
long long dist[MAXK][MAXN];
set< int > s;
vector< pair<int,int> > G[MAXN];

struct edge
{
        int to , w , nxt;
} e[MAXN << 2];
struct query
{
        int s , t , id;
} a[MAXN];

template  inline void chkmax(T &x,T y) { x = max(x,y); }
template  inline void chkmin(T &x,T y) { x = min(x,y); }
template  inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline void addedge(int u,int v,int w)
{
        tot++;
        e[tot] = (edge){v,w,head[u]};
        head[u] = tot;
}
inline int get_root(int x)
{
        if (f[x] == x) return x;
        else return f[x] = get_root(f[x]);
}
inline void dfs(int u,int fa)
{
        for (int i = 1; i < MAXLOG; i++)
        {
                if (depth[u] < (1 << i)) break;
                anc[u][i] = anc[anc[u][i - 1]][i - 1];
        }
        for (int i = head[u]; i; i = e[i].nxt)
        {
                int v = e[i].to , w = e[i].w;        
                if (v == fa) continue;
                depth[v] = depth[u] + 1;
                anc[v][0] = u;
                sum[v] = sum[u] + w;
                dfs(v,u);
        }        
}
inline int lca(int x,int y)
{
        if (depth[x] > depth[y]) swap(x,y);
        for (int i = MAXLOG - 1; i >= 0; i--)
        {
                if (depth[anc[y][i]] >= depth[x])
                        y = anc[y][i];
        }
        if (x == y) return x;
        for (int i = MAXLOG - 1; i >= 0; i--)
        {
                if (anc[x][i] != anc[y][i])
                        x = anc[x][i] , y = anc[y][i];
        } 
        return anc[x][0];
}

inline long long dis(int x,int y)
{
        return sum[x] + sum[y] - 2 * sum[lca(x,y)];
}
inline void dijkstra(int s,int k)
{
        static bool visited[MAXN];
        priority_queue< pair<long long,int> > q;
        for (int i = 1; i <= n; i++) 
        {
                dist[k][i] = inf;
                visited[i] = false;
        }
        dist[k][s] = 0;
        q.push(make_pair(0,s));
        while (!q.empty())
        {
                int cur = q.top().second;
                q.pop();
                if (visited[cur]) continue;
                visited[cur] = true;
                for (unsigned i = 0; i < G[cur].size(); i++)
                {
                        int v = G[cur][i].first , w = G[cur][i].second;
                        if (dist[k][cur] + w < dist[k][v])
                        {
                                dist[k][v] = dist[k][cur] + w;
                                q.push(make_pair(-dist[k][v],v));
                        }
                }
        }
}
int main()
{
        
        read(n); read(m);
        for (int i = 1; i <= m; i++)
        {
                read(u[i]); 
                read(v[i]); 
                read(w[i]);
                G[u[i]].push_back(make_pair(v[i],w[i]));
                G[v[i]].push_back(make_pair(u[i],w[i]));
        }
        for (int i = 1; i <= n; i++) f[i] = i;
        for (int i = 1; i <= m; i++)
        {
                int x = get_root(u[i]) , y = get_root(v[i]);
                if (x != y)
                {
                        addedge(u[i],v[i],w[i]);
                        addedge(v[i],u[i],w[i]);
                        f[x] = y;
                        mark[i] = true;
                } 
        }
        for (int i = 1; i <= m; i++)
        {
                if (!mark[i])
                {
                        s.insert(u[i]);
                        s.insert(v[i]);
                }
        }
        dfs(1,-1);
        for (set< int > :: iterator it = s.begin(); it != s.end(); it++) dijkstra(*it,++k);
        read(q);
        while (q--)
        {
                int u , v;
                read(u); read(v);
                long long ans = dis(u,v);
                for (int i = 1; i <= k; i++) chkmin(ans,dist[i][u] + dist[i][v]);
                printf("%I64d\n",ans); 
        } 
        
        return 0;
    
}

 

转载于:https://www.cnblogs.com/evenbao/p/9734215.html

你可能感兴趣的:([Codeforces 1051F] The Shortest Statement)