码迷,mamicode.com
首页 > 其他好文 > 详细

[HAOI 2012] Road

时间:2019-03-15 23:03:34      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:ret   单源最短路   pen   https   sig   nta   main   cal   unsigned   

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=2750

[算法]

        考虑计算每个点对每条边的贡献

        对于每个点首先运行SPFA或Dijkstra单源最短路 , 建出以该点为根的最短路树(图)

        由于最短路图是一个DAG(有向无环图) , 我们可以求出其拓扑序列 , 对于每个点i , 计算 :

        CNT1 : 从枚举的点到该点的 , 最短路图上的路径条数

        CNT2 : 从该点出发 , 在最短路图上 , 有多少条路径

        对于每条在最短路图上的边 , 用乘法原理计算贡献即可

        时间复杂度 : O(NM)

[代码]

       

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N = 5010;
const int inf = 2e9;
const int P = 1e9 + 7;

struct edge
{
        int to , w , nxt;
} e[N << 1];

int n , m , tot;
int dist[N] , cnta[N] , cntb[N] , u[N] , v[N] , w[N] , head[N] , topo[N] , ans[N];
bool ok[N];

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> 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 void spfa(int S)
{
        static bool inq[N];
        queue< int > q;
        for (int i = 1; i <= n; ++i)
        {
                dist[i] = inf;
                inq[i] = false;
                cnta[i] = cntb[i] = 0;
        }
        for (int i = 1; i <= m; ++i) ok[i] = false;
        q.push(S);
        inq[S] = true;
        dist[S] = 0;
        while (!q.empty())
        {
                int cur = q.front();
                q.pop();
                inq[cur] = false;
                for (int i = head[cur]; i; i = e[i].nxt)
                {
                        int v = e[i].to , w = e[i].w;
                        if (dist[cur] + w < dist[v])
                        {    
                                dist[v] = dist[cur] + w;
                                if (!inq[v])
                                {
                                        inq[v] = true;
                                        q.push(v);
                                }
                        } 
                }
        }
        for (int i = 1; i <= m; ++i)
                if (dist[u[i]] + w[i] == dist[v[i]]) ok[i] = true;
} 
inline void calc()
{
        queue< int > q;
        static int deg[N];
        for (int i = 1; i <= n; ++i)
                deg[i] = 0;
        for (int i = 1; i <= m; ++i)
                if (ok[i]) ++deg[v[i]];
        for (int i = 1; i <= n; i++)
                if (!deg[i]) 
                {
                        cnta[i] = 1;
                        q.push(i);
                }
        int M = 0;
        while (!q.empty())
        {
                int cur = q.front();
                q.pop();
                topo[++M] = cur;
                for (int i = head[cur]; i; i = e[i].nxt)
                {
                        int v = e[i].to;
                        if (!ok[i]) continue;
                        cnta[v] = (cnta[v] + cnta[cur]) % P;
                        if (!(--deg[v])) q.push(v);
                }
        }
        for (int i = n; i >= 1; i--)
        {
                ++cntb[topo[i]];
                for (int j = head[topo[i]]; j; j = e[j].nxt)
                {
                        int v = e[j].to;
                        if (!ok[j]) continue;
                        cntb[topo[i]] = (cntb[topo[i]] + cntb[v]) % P;
                }
        }
}
inline void update(int S)
{
        spfa(S);
        calc();
        for (int i = 1; i <= m; ++i)
                if (ok[i]) ans[i] = (ans[i] + 1ll * cnta[u[i]] * cntb[v[i]] % P) % P;        
}

int main()
{
        
        read(n); read(m);
        for (int i = 1; i <= m; ++i)
        {
                read(u[i]); read(v[i]); read(w[i]);
                addedge(u[i] , v[i] , w[i]);
        }
        for (int i = 1; i <= n; ++i) update(i);
        for (int i = 1; i <= m; ++i) printf("%d\n" , ans[i]);
        
        return 0;
    
}

 

[HAOI 2012] Road

标签:ret   单源最短路   pen   https   sig   nta   main   cal   unsigned   

原文地址:https://www.cnblogs.com/evenbao/p/10540041.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!