BZOJ 2750: [HAOI2012]Road( 最短路 )

对于每个点都跑最短路, 然后我们得到了个DAG, 在这DAG上更新每条边的答案.

考虑e(u, v)∈DAG对答案的贡献:  假设从S到u得路径数为A[u], 从v出发到达任意点的路径数为B[v], 那么e(u, v)的答案可以加上A[u] * B[v](显然).

A可以按拓扑序递推得到, B可以通过记忆化搜索得到, 都是O(m). 所以总时间复杂度O(nmlogn + nm)

-------------------------------------------------------------------------------------

#include<bits/stdc++.h>

#define rep(i, n) for(int i = 0; i < n; i++)

#define clr(x, c) memset(x, c, sizeof(x))

#define REP(x) for(edge* e = head[x]; e; e = e->next)

#define foreach(e, x) for(__typeof(x.begin()); e != x.end(); e++)

#define mod(x) ((x) %= MOD)

using namespace std;

const int maxn = 1509, maxm = 5009;

const int MOD = 1000000007;

struct edge {

int to, w, num;

edge* next;

} E[maxm], *pt = E, *head[maxn];

inline void addedge(int u, int v, int d, int _) {

pt->to = v, pt->w = d, pt->num = _;

pt->next = head[u];

head[u] = pt++;

}

struct node {

int x, w;

bool operator < (const node &t) const {

return w > t.w;

}

};

int d[maxn], cnt[maxn], ans[maxm], A[maxn], B[maxn], n;

void dijkstra(int S) {

rep(i, n) d[i] = MOD;

d[S] = 0;

priority_queue<node> Q;

Q.push( (node) {S, 0} );

while(!Q.empty()) {

node t = Q.top(); Q.pop();

if(d[t.x] != t.w) continue;

REP(t.x) if(d[t.x] + e->w < d[e->to]) {

d[e->to] = d[t.x] + e->w;

Q.push( (node) {e->to, d[e->to]} );

}

}

}

// get B

int dp(int x) {

if(B[x]) return B[x];

REP(x) if(d[e->to] == d[x] + e->w)

mod(B[x] += dp(e->to));

return ++B[x];

}

//get A

void DFS(int x) {

REP(x) if(d[e->to] == d[x] + e->w) {

mod(A[e->to] += A[x]);

if(!--cnt[e->to]) DFS(e->to);

}

}

void dfs(int x) {

REP(x) if(d[e->to] == d[x] + e->w)

if(!cnt[e->to]++) dfs(e->to);

}

void work(int x) {

dijkstra(x);

clr(cnt, 0), clr(A, 0), clr(B, 0);

dfs(x), dp(x), A[x] = 1, DFS(x);

rep(i, n)

REP(i) if(d[i] + e->w == d[e->to])

mod(ans[e->num] += 1LL * A[i] * B[e->to] % MOD);

}

inline int read() {

char c = getchar();

for(; !isdigit(c); c = getchar());

int ans = 0;

for(; isdigit(c); c = getchar())

ans = ans * 10 + c - ‘0‘;

return ans;

}

int main() {

freopen("test.in", "r", stdin);

int m;

clr(head, 0), clr(ans, 0);

cin >> n >> m;

rep(i, m) {

int u = read() - 1, v = read() - 1, w = read();

addedge(u, v, w, i);

}

rep(i, n) work(i);

for(int* t = ans; t != ans + m; t++)

printf("%d\n", *t);

return 0;

}

-------------------------------------------------------------------------------------

2750: [HAOI2012]Road

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 356  Solved: 163
[Submit][Status][Discuss]

Description

C国有n座城市,城市之间通过m条单向道路连接。一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小。两条最短路不同,当且仅当它们包含的道路序列不同。我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路。现在,这个任务交给了你。

Input

第一行包含两个正整数n、m
接下来m行每行包含三个正整数u、v、w,表示有一条从u到v长度为w的道路

Output

输出应有m行,第i行包含一个数,代表经过第i条道路的最短路的数目对1000000007取模后的结果

Sample Input

4 4
1 2 5
2 3 5
3 4 5
1 4 8

Sample Output

2
3
2
1

HINT

数据规模

30%的数据满足:n≤15、m≤30

60%的数据满足:n≤300、m≤1000

100%的数据满足:n≤1500、m≤5000、w≤10000

Source

时间: 2024-08-24 22:22:02

BZOJ 2750: [HAOI2012]Road( 最短路 )的相关文章

bzoj 2750: [HAOI2012]Road【spfa+dfs】

枚举起点做spfa,然后一条边在最短路上的条件是dis[e[i].to]==dis[u]+e[i].va,所以每次spfa完之后,dfs出a[i]表示经过i点的最短路的起点数,b[i]表示经过i点的最短路的终点数,一条边(u,v)在当前起点下的答案就是a[u]*b[v],最终答案是总和 因为最短路构成一个DAG,所以a是按照类似拓扑序的东西来dfs的 #include<iostream> #include<cstdio> #include<queue> #include

bzoj2750: [HAOI2012]Road

2750: [HAOI2012]Road Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 651  Solved: 302[Submit][Status][Discuss] Description C国有n座城市,城市之间通过m条单向道路连接.一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同.我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路

HDU 1596 find the safest road (最短路)

find the safest road Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 6973    Accepted Submission(s): 2469 Problem Description XX星球有很多城市,每个城市之间有一条或多条飞行通道,但是并不是所有的路都是很安全的,每一条路有一个安全系数s,s是在 0 和 1

BZOJ 2750 HAOI 2012 Road 高速公路 最短路

题意: 给出一个有向图,求每条边有多少次作为最短路上的边(任意的起始点). 范围:n <= 1500, m <= 5005 分析: 一个比较容易想到的思路:以每个点作为起点,做一次SPFA,记f[i]表示从点S到达点i的最短路数,g[i]表示从点i到达点T的最短路数. 那么对于任意一条边,答案就是∑f[u]*g[v] 剩下的问题就是f.g怎么求. f必须从前面的递推过来,如果前面的没有递推完,那么就不能递推当前点,需要记录每个点可以从多少个点递推过来,这个一次dfs就可以完成. g可以记忆化搜

BZOJ 3040: 最短路(road) ( 最短路 )

本来想学一下配对堆的...结果学着学着就偏了... 之前 kpm 写过这道题 , 前面的边不理它都能 AC .. 我也懒得去写前面的加边了... 用 C++ pb_ds 库里的 pairing_heap 水过去的... ---------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #

BZOJ 2752: [HAOI2012]高速公路(road) [线段树 期望]

2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1219  Solved: 446[Submit][Status][Discuss] Description Y901高速公路是一条重要的交通纽带,政府部门建设初期的投入以及使用期间的养护费用都不低,因此政府在这条高速公路上设立了许多收费站.Y901高速公路是一条由N-1段路以及N个收费站组成的东西向的链,我们按照由西向东的顺序将收费站依次编号为1

Road(bzoj 2750)

Description C国有n座城市,城市之间通过m条单向道路连接.一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同.我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路.现在,这个任务交给了你. Input 第一行包含两个正整数n.m接下来m行每行包含三个正整数u.v.w,表示有一条从u到v长度为w的道路 Output 输出应有m行,第i行包含一个数,代表经过第i条道路的最短路的数目对1

BZOJ 2750 Road

最短路+dp. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #define maxv 1550 #define maxe 10050 #define inf 0x7f7f7f7f #define mod 1000000000 using namespace std; struct edge { long long

BZOJ 2752 [HAOI2012]高速公路(road) 线段树

题意:链接 方法:线段树 解析: 这道题刚开始脑抽想了个O(n/2*(logn)*m)的脑抽算法就写上交了=-= 然而当时我神奇地在草纸上写了个O(sqrt(n)/2*(logn)*m).. 当时在想另一个什么分块的什么东西就没过大脑=-= 然后开始找规律呗. 不妨把权值安到点上. 之后考虑一个点的贡献是什么. 其左边有多少个点,右边有多少个点的乘积. 这很显然啊,就是在枚举大长线段的左右端点啊.. 所以假设某个点的权值是val 那么就是val[i](i-x+1)(y-i+1)对吧. 之后就是展