P2685 [TJOI2012]桥
思路:
先求出最短路: d1[u] : u 到 1 的最短路, d2[u] : u 到 n 的最短路
再求出一条从 1 到 n 的最短路链,然后从链上的每一个点出发dfs, 求出:
l[u] : u 到 1 的最短路径过中和链的交点(离 1 最近的)
r[u] : u 到 n 的最短路径过中和链的交点(离 n 最近的)
然后对于一条非链上的边( u -> v ),边权为 w ,对于链上的 l[u] 到 r[v] 之间的边任意删一条边,
最短路都有可能变成 d1[u] + w + d2[v] 然后在链上维护这个的最小值,就能知道删掉链上的每条边对最短路的影响
代码:
#pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC optimize(4) #include<bits/stdc++.h> using namespace std; #define y1 y11 #define fi first #define se second #define pi acos(-1.0) #define LL long long //#define mp make_pair #define pb push_back #define ls rt<<1, l, m #define rs rt<<1|1, m+1, r #define ULL unsigned LL #define pll pair<LL, LL> #define pli pair<LL, int> #define pii pair<int, int> #define piii pair<pii, int> #define pdd pair<double, double> #define mem(a, b) memset(a, b, sizeof(a)) #define debug(x) cerr << #x << " = " << x << "\n"; #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); //headconst int N = 1e5 + 5; const int INF = 0x3f3f3f3f; int n, m, u, v, w, tot, d1[N], d2[N], link[N], id[N], l[N], r[N], a[N]; int head[N], cnt = 0; bool vis[N*2]; struct edge {int to, w, nxt; }edge[N*4]; void add(int u, int v, int w) {edge[++cnt] = {v, w, head[u]};head[u] = cnt; } priority_queue<pii, vector<pii>, greater<pii> > q; int tree[N<<2], lazy[N<<2]; void push_up(int rt) {tree[rt] = min(tree[rt<<1], tree[rt<<1|1]); } void push_down(int rt) {tree[rt<<1] = min(tree[rt<<1], lazy[rt]);tree[rt<<1|1] = min(tree[rt<<1|1], lazy[rt]);lazy[rt<<1] = min(lazy[rt<<1], lazy[rt]);lazy[rt<<1|1] = min(lazy[rt<<1|1], lazy[rt]);lazy[rt] = INF; } void build(int rt, int l, int r) {lazy[rt] = INF;if(l == r) {tree[rt] = INF;return ;}int m = l+r >> 1;build(ls);build(rs);push_up(rt); } void down(int rt, int l, int r) {if(l == r) {a[l] = tree[rt];return ;}if(lazy[rt] != INF) push_down(rt);int m = l+r >> 1;down(ls);down(rs);push_up(rt); } void update(int L, int R, int x, int rt, int l, int r) {if(L <= l && r <= R) {tree[rt] = min(tree[rt], x);lazy[rt] = min(lazy[rt], x);return ;}if(lazy[rt] != INF) push_down(rt);int m = l+r >> 1;if(L <= m) update(L, R, x, ls);if(R > m) update(L, R, x, rs);push_up(rt); }void Dijkstra(int s, int *d) {for (int i = 1; i <= n; ++i) d[i] = INF;d[s] = 0;q.push({0, s});while(!q.empty()) {pii p = q.top();q.pop();int u = p.se;if(d[u] < p.fi) continue;for (int i = head[u]; i; i = edge[i].nxt) {int v = edge[i].to;int w = edge[i].w;if(d[v] > p.fi + w) {d[v] = p.fi + w;q.push({d[v], v});}}} } void dfs(int u, int s, int *bl, int *d) {bl[u] = s;for (int i = head[u]; i; i = edge[i].nxt) {int v = edge[i].to;int w = edge[i].w;//if(vis[(i+1)/2]) continue;if(bl[v] == 0 && id[v] == 0 && d[u] + w == d[v]) dfs(v, s, bl, d);} } int main() {scanf("%d %d", &n, &m);for (int i = 1; i <= m; ++i) {scanf("%d %d %d", &u, &v, &w);add(u, v, w);add(v, u, w);}Dijkstra(1, d1);Dijkstra(n, d2);tot = 0;u = 1;while(u != n) {link[++tot] = u;id[u] = tot;for (int i = head[u]; i; i = edge[i].nxt) {int v = edge[i].to;int w = edge[i].w;if(d2[v] + w == d2[u]){vis[(i+1)/2] = true;u = v;break;}}}link[++tot] = n;id[n] = tot;for (int i = 1; i <= tot; ++i) dfs(link[i], link[i], l, d1);for (int i = tot; i >= 1; --i) dfs(link[i], link[i], r, d2);build(1, 1, tot-1);for (int u = 1; u <= n; ++u) {for (int i = head[u]; i; i = edge[i].nxt) {int v = edge[i].to;int w = edge[i].w;if(!vis[(i+1)/2]) {if(id[l[u]] < id[r[v]]) update(id[l[u]], id[r[v]]-1, d1[u] + w + d2[v], 1, 1, tot-1);}}}down(1, 1, tot-1);int ans = 0, cnt = 0;for (int i = 1; i < tot; ++i) {if(a[i] > ans) {ans = a[i];cnt = 1;}else if(a[i] == ans) {cnt++;}}if(ans == d1[n]) cnt = m;printf("%d %d\n", ans, cnt);return 0; }