P2934 [USACO09JAN]安全出行Safe Travel

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\n",ans[i] - dis[i]);
146     return 0;
147 }

 

posted @ 2018-09-10 17:30  MJT12044  阅读(197)  评论(0编辑  收藏  举报