[无聊测试赛] T12 道路
by _Zhumingrui
这道题的大致题意是:根据最短路求边的拓扑图,然后求出每个边的入度。
我用 Dijkstra 求最短路,顺便建好图。之后使用 BFS 来递推拓扑条件,保存至 ans 数组。
注意事项:
使用 long long,你们懂得。
这个做法需要倒序遍历边,因为只有倒序遍历能满足拓扑序。
本代码需要 \(O_2\) 优化 才可通过本题。
Code:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdlib>
using namespace std;
namespace {
constexpr const int N = 2333;
constexpr int M = 5555;
unsigned mod = 1000000007;
//vector清空边不容易,用前向星快好多
struct {
struct {
int v, n, w;
}edge[M];
int link[N], cnt;
inline void add(const int& u, const int& v, const int& w) {
edge[++cnt].w = w;
edge[cnt].v = v;
edge[cnt].n = link[u];
link[u] = cnt;
}
}a, b; //建两个图,一个(A)是原图,另一个(B)是DAG
int n, m;
struct ___ {
int w, v;
inline bool operator <(const ___& b) const {
return w > b.w;
}
};
priority_queue<___> heap;
queue<int> q;
int d[N];
bool book[N];
int rrank[N];
long long dp[N], ans[M], dp1[N];
inline void dijkstra(const int& s) {
b.cnt = 0;
for (int i = 1; i <= n; i++) {
d[i] = 0x3f3f3f3f;
book[i] = false;
dp[i] = 1;
rrank[i] = 0;
b.link[i] = 0;
dp1[i] = 0;
}
d[s] = 0;
dp1[s] = 1;
heap.push({ 0,s });
while (!heap.empty()) {
int now = heap.top().v;
heap.pop();
if (book[now])continue;
book[now] = true;
//倒着推
int nxt = a.link[now];
while (nxt) {
const int& v = a.edge[nxt].v;
const int& val = a.edge[nxt].w;
if (!book[v]) {
//如果相等,加上一条
if (d[v] == d[now] + val) {
b.add(v, now, nxt);
dp1[v] = (dp1[v] + dp1[now]) % mod;
}
//如果更好,就把边拆了,重新加上条
if (d[v] > d[now] + val) {
b.link[v] = 0;
b.add(v, now, nxt);
dp1[v] = dp1[now];
d[v] = d[now] + val;
heap.push({ d[v], v });
}
}
nxt = a.edge[nxt].n;
}
}
}
inline void toposort() {
//求入度
for (int i = 1; i <= n; i++)
for (int p = b.link[i]; p; p = b.edge[p].n)
rrank[b.edge[p].v]++;
for (int i = 1; i <= n; i++)
if (rrank[i] == 0)
q.push(i);
//递推
while (!q.empty()) {
int now = q.front();
q.pop();
int nxt = b.link[now];
while (nxt) {
const int& v = b.edge[nxt].v;
const int& w = b.edge[nxt].w;
dp[v] = (dp[v] + dp[now]) % mod;
ans[w] = (ans[w] + dp[now] * dp1[v]) % mod;
rrank[v]--;
if (rrank[v] == 0)
q.push(v);
nxt = b.edge[nxt].n;
}
}
}
int u, v, w;
inline int get() {
static unsigned char a;
static char st[100], eof;
if (a == 100 || a == 0)
if (!eof) {
if (fread(st, sizeof(char), 100, stdin) < 100)
eof = 1;
a = 0;
}
else {
return -1;
}
return st[a++];
}
#ifdef _DEBUG
#define get() getchar()
#endif
inline void read(int& ans) {
ans = 0x00000000;
char ch = get();
while ((ch < '0') || (ch > '9'))ch = get();
while ((ch >= '0') && (ch <= '9')) {
ans = (ans << 3) + (ans << 1) + (ch & 15);
ch = get();
}
}
}
int main() {
#define int register int
read(n), read(m);
for (int i = 1; i <= m; i++) {
read(u), read(v), read(w);
a.add(u, v, w);
}
for (int i = 1; i <= n; i++) {
dijkstra(i);
toposort();
}
for (int i = 1; i <= m; i++)
printf("%d\n", ans[i]);
return 0;
#undef int
}