P2934 [USACO09JAN]安全出行Safe Travel
https://www.luogu.org/problemnew/show/P2934
分析:
建出最短路树,然后考虑一条非树边u,v,w,它可以让u->lca的路径上的点x的答案更新为dis[v]+dis[u]+w-dis[x]。为从1走到v(dis[v]),从v走到u(+w),从u走到x,(dis[u]-dis[x])。
然后对于每条非树边,按照dis[v]+dis[u]+w排序,然后会发现每个点只会更新一次,然后用并查集维护。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const int N = 400100; 20 const int INF = 1e9; 21 22 struct Edge{ 23 int u,v,w,lca; 24 Edge() {} 25 Edge(int a,int b,int c,int d) { u = a, v = b, w = c; lca = d;} 26 bool operator < (const Edge &A) const { 27 return w < A.w; 28 } 29 }e[N]; 30 int fa[N], far[N], ans[N], n; 31 32 namespace ShortestPath{ 33 #define pa pair<int,int> 34 #define mp(a,b) make_pair(a,b) 35 priority_queue< pa, vector< pa >, greater< pa > >q; 36 int head[N], nxt[N], to[N], len[N], dis[N], En; 37 bool vis[N]; 38 void add_edge(int u,int v,int w) { 39 ++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En; 40 ++En; to[En] = u; len[En] = w; nxt[En] = head[v]; head[v] = En; 41 } 42 void dijkstra() { 43 for (int i=1; i<=n; ++i) dis[i] = INF, vis[i] = false; 44 dis[1] = 0; 45 q.push(mp(dis[1],1)); 46 while (!q.empty()) { 47 pa now = q.top(); q.pop(); 48 int u = now.second; 49 if (vis[u]) continue; 50 vis[u] = true; 51 for (int i=head[u]; i; i=nxt[i]) { 52 int v = to[i]; 53 if (dis[v] > dis[u] + len[i]) { 54 fa[v] = u; 55 dis[v] = dis[u] + len[i]; 56 q.push(mp(dis[v], v)); // 居然写成了mp(v,dis[v])!!! 57 } 58 } 59 } 60 } 61 } 62 namespace Tree_Chain{ 63 int IIIII; 64 int siz[N], son[N], bel[N], deth[N]; 65 vector<int> T[N]; 66 void dfs1(int u) { 67 siz[u] = 1; 68 deth[u] = deth[fa[u]] + 1; 69 for (int sz=T[u].size(),i=0; i<sz; ++i) { 70 int v = T[u][i]; 71 if (v == fa[u]) continue; 72 dfs1(v); 73 siz[u] += siz[v]; 74 if (!son[u] || siz[v] > siz[son[u]]) son[u] = v; 75 } 76 } 77 void dfs2(int u,int top) { 78 bel[u] = top; 79 if (!son[u]) return; 80 dfs2(son[u], top); 81 for (int sz=T[u].size(),i=0; i<sz; ++i) { 82 int v = T[u][i]; 83 if (v == fa[u] || v == son[u]) continue; 84 dfs2(v, v); 85 } 86 } 87 int LCA(int u,int v) { 88 while (bel[u] != bel[v]) { 89 if (deth[bel[u]] < deth[bel[v]]) swap(u, v); 90 u = fa[bel[u]]; 91 } 92 if (deth[u] < deth[v]) return u; 93 return v; 94 } 95 void Main() { 96 for (int i=2; i<=n; ++i) T[fa[i]].push_back(i); 97 dfs1(1); 98 dfs2(1, 1); 99 } 100 } 101 using namespace ShortestPath; 102 using namespace Tree_Chain; 103 104 int find(int x) { 105 return x == far[x] ? x : far[x] = find(far[x]); 106 } 107 void Merge(int u,int v) { 108 u = find(u), v = find(v); 109 if (u != v) far[u] = v; 110 } 111 void update(int u,int lca,int v) { 112 u = find(u); 113 int x = fa[u]; 114 while (deth[u] > deth[lca]) { 115 ans[u] = v; Merge(u, x); 116 u = find(u); x = fa[u]; 117 } 118 } 119 int main() { 120 n = read(); int m = read(); 121 for (int i=1; i<=m; ++i) { 122 int u = read(), v = read(), w = read(); 123 add_edge(u, v, w); 124 } 125 126 ShortestPath::dijkstra(); 127 Tree_Chain::Main(); 128 129 int cnt = 0; 130 for (int u=1; u<=n; ++u) { 131 for (int i=head[u]; i; i=nxt[i]) { 132 int v = to[i]; 133 if (v > u && u != fa[v] && v != fa[u]) 134 e[++cnt] = Edge(u, v, dis[u] + dis[v] + len[i], LCA(u,v)); // e[i].w,zz的减了一个dis[lca] 135 } 136 } 137 for (int i=1; i<=n; ++i) far[i] = i, ans[i] = INF; 138 sort(e + 1, e + cnt + 1); 139 for (int i=1; i<=cnt; ++i) { 140 update(e[i].u, e[i].lca, e[i].w); 141 update(e[i].v, e[i].lca, e[i].w); 142 } 143 for (int i=2; i<=n; ++i) 144 if (ans[i] == INF) puts("-1"); 145 else printf("%d ",ans[i] - dis[i]); 146 return 0; 147 }