题目传送门
Please note that we changed the sample input 1 a little bit to fit the illustration. The answer for either version is correct though. PDF updated. Sorry for troubles caused.
Will you give all you can give
So that our banner may advance?
Some will fall and some will live
Will you stand up and take your chance?
The blood of the martyrs
Will water the meadows of France!
A solitary spark can start a prairie fire.
You are given a weighted connected undirected graph with nn vertices and mm edges. You know that someone light up a fire at vertex 11, which will burn the current position into dust immediately and expand to adjacent places at the speed 11 mile per second. The fire will split at the vertices to all those edges who have not been lighten up, and will cause a blast when at least two fires meet at the same point.
Revolutionaries love explosions. They want you to count the number of explosions that will happen on the graph.
The first line contains integers n , m ( 1 ≤ n ≤ 3 × 1 0 5 , 0 ≤ m ≤ 1 0 6 ) n,m (1 \leq n \leq 3 \times 10 ^ 5, 0 \leq m \leq 10 ^ 6) n,m(1≤n≤3×105,0≤m≤106) - the number of vertices.
Each of the next mm lines contains 3 3 3 integers u i , v i , w i ( 1 ≤ u i , v i ≤ n , 1 ≤ w i ≤ 9 ) u_i, v_i, w_i (1 \leq u_i, v_i \leq n, 1 \leq w_i \leq 9) ui,vi,wi(1≤ui,vi≤n,1≤wi≤9) - the ends of the i -th i\text{-th} i-th edge and the weight of the i -th i\text{-th} i-th edge.
It’s guaranteed that the graph is connected.
The graph may contain self loops and multiple edges. Example 11 shows the method to deal with them.
The size of input file may be large. Please, do not read input by too slow ways.
Output the number of explosions that will happen on the graph in a single line.
2 3
1 1 1
1 2 1
1 2 1
4 5
1 2 1
1 3 1
2 3 1
2 4 1
3 4 1
2
2
Here’s the illustration for example 1:
Here’s the illustration for example 2:
#include
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int maxn = 3e5 + 7;
const int maxm = 1e6 + 7;
struct P {
int to, val;
P() { to = val = 0; }
P(int a, int b) :to(a), val(b) {};
bool operator < (const P& t)const { return val > t.val; }
};
vector<P> G[maxm];
int dis[maxn];
bool vis[maxn];
void add(int u, int v, int w) {
G[u].push_back(P(v, w));
if (u != v) G[v].push_back(P(u, w));
}
void dijk() {
memset(dis, 0x3f, sizeof dis);
memset(vis, false, sizeof vis);
priority_queue<P> q;
q.push(P(1, 0)); dis[1] = 0;
while (!q.empty()) {
P tmp = q.top(); q.pop();
if (vis[tmp.to]) continue;
vis[tmp.to] = true;
for (int i = 0; i < G[tmp.to].size(); ++i) {
int pos = G[tmp.to][i].to;
int value = G[tmp.to][i].val;
if (dis[pos] > dis[tmp.to] + value) {
dis[pos] = dis[tmp.to] + value;
q.push(P(pos, dis[pos]));
}
}
}
}
int main() {
ios;
int n, m; while (cin >> n >> m) {
for (int i = 1; i <= m; ++i) {
int u, v, w; cin >> u >> v >> w;
add(u, v, w); // 无向图
}
dijk(); // 跑一边最短路
int ans = 0;
for (int i = 1; i <= n; ++i) {
int cnt = 0;
for (P v : G[i]) { // v:点i的邻接点+权值,前驱、后继。
if (dis[i] == dis[v.to] + v.val) // 找交点爆炸
++cnt; // v->i和dis[i]相同,v可以是最短路上的点
else if (i >= v.to && dis[i] + v.val > dis[v.to] && dis[v.to] + v.val > dis[i]) ++ans;
}
if (cnt > 1) ++ans; // 俩以上前驱等距离,在交点爆炸1次
}
cout << ans << endl;
}
}