Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement

题目链接:The Shortest Statement

今天又在群里看到一个同学问$n$个$n$条边,怎么查询两点直接最短路。看来这种题还挺常见的。

为什么最终答案要从42个点的最短路(到$x,y$)之和,还有$x,y$到$LCA(x,y)$的距离里面取呢?

就是如果走非树边,那么一定要走42个点中的一个,不走树边,就是LCA求了。

我写的太蠢了,还写生成树,看大家都是LCA中的dfs直接标记下就行了。

验证了算法的正确,我又试了试把每条非树边只加一个点,也是AC的,其实想了想,确实正确。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 typedef long long ll;
  5 const int maxn = 1e5 + 5;
  6 const ll INF = 0x3f3f3f3f3f3f3f3f;
  7 struct edge{
  8     int to;
  9     ll cost;
 10     friend bool operator < (edge A,edge B){
 11         return A.cost > B.cost;
 12     }
 13 };
 14 int u[maxn], v[maxn], w[maxn], vis[maxn];
 15 vector<int> flag;
 16 ll d[43][maxn];
 17 vector<edge> g[maxn];
 18 bool done[maxn];
 19 void dijkstra(ll d[], vector<edge> g[], bool done[], int s){
 20     fill(d,d + maxn, INF);
 21     fill(done, done + maxn, false);
 22     d[s] = 0;
 23     priority_queue<edge> q;
 24     q.push((edge){s,0});
 25     while(!q.empty()){
 26         edge cur = q.top(); q.pop();
 27         int v = cur.to;
 28         if(done[v]) continue;
 29         done[v] = true;
 30         for(int i = 0; i<g[v].size(); i++){
 31             edge e = g[v][i];
 32             if(d[e.to]>d[v]+e.cost){
 33                 d[e.to] = d[v]+e.cost;
 34                 q.push((edge){e.to,d[e.to]});
 35             }
 36         }
 37     }
 38 }
 39 ///加边
 40 int cnt, h[maxn];
 41 struct node
 42 {
 43     int to, pre, v;
 44 } e[maxn << 1];
 45 void init()
 46 {
 47     cnt = 0;
 48     memset(h, 0, sizeof(h));
 49 }
 50 void add(int from, int to, int v)
 51 {
 52     cnt++;
 53     e[cnt].pre = h[from]; ///5-->3-->1-->0
 54     e[cnt].to = to;
 55     e[cnt].v = v;
 56     h[from] = cnt;
 57 }
 58 ///LCA
 59 ll dist[maxn];
 60 int dep[maxn];
 61 int anc[maxn][33]; ///2分的父亲节点
 62 void dfs(int u, int fa)
 63 {
 64     for(int i = h[u]; i; i = e[i].pre)
 65     {
 66         int v = e[i].to;
 67         if(v == fa) continue;
 68         dist[v] = dist[u] + e[i].v;
 69         dep[v] = dep[u] + 1;
 70         anc[v][0] = u;
 71         dfs(v, u);
 72     }
 73 }
 74 void LCA_init(int n)
 75 {
 76     for(int j = 1; (1 << j) < n; j++)
 77         for(int i = 1; i <= n; i++) if(anc[i][j-1])
 78         anc[i][j] = anc[anc[i][j-1]][j-1];
 79 }
 80 int LCA(int u, int v)
 81 {
 82     int log;
 83     if(dep[u] < dep[v]) swap(u, v);
 84     for(log = 0; (1 << log) < dep[u]; log++);
 85     for(int i = log; i >= 0; i--)
 86         if(dep[u] - (1 << i) >= dep[v]) u = anc[u][i];
 87     if(u == v) return u;
 88     for(int i = log; i >= 0; i--)
 89         if(anc[u][i] && anc[u][i] != anc[v][i])
 90             u = anc[u][i], v = anc[v][i];
 91     return anc[u][0];
 92 }
 93 
 94 int pre[maxn];
 95 int Find(int x)
 96 {
 97     if(x == pre[x]) return x;
 98     else return pre[x] = Find(pre[x]);
 99 }
100 int main()
101 {
102     int n, m; scanf("%d %d", &n, &m);
103     for(int i = 1; i <= m; i++)
104     {
105         scanf("%d %d %d", &u[i], &v[i], &w[i]);
106         g[u[i]].push_back({v[i], w[i]});
107         g[v[i]].push_back({u[i], w[i]});
108     }
109     ///先找生成树
110     for(int i = 1; i <= n; i++) pre[i] = i;
111     for(int i = 1; i <= m; i++)
112     {
113         int x = Find(u[i]);
114         int y = Find(v[i]);
115         if(x != y)
116         {
117             pre[x] = y;
118         }
119         else flag.push_back(u[i]), flag.push_back(v[i]), vis[i] = 1;
120     }
121     ///对至多42个点跑最短路
122     sort(flag.begin(), flag.end());
123     flag.erase(unique(flag.begin(), flag.end()), flag.end());
124     for(int i = 0; i < flag.size(); i++)
125     {
126         dijkstra(d[i], g, done, flag[i]);
127     }
128     ///跑LCA
129     init();
130     for(int i = 1; i <= m; i++)
131     {
132         if(!vis[i]) add(u[i], v[i], w[i]), add(v[i], u[i], w[i]);
133     }
134     dist[1] = 0;
135     dfs(1, 0);
136     LCA_init(n);
137     int Q; scanf("%d", &Q);
138     ///查询
139     while(Q--)
140     {
141         int x, y; scanf("%d %d", &x, &y);
142         ll ans = dist[x] + dist[y] - 2LL * dist[LCA(x, y)];
143         for(int i = 0; i < flag.size(); i++)
144         {
145             ans = min(ans, d[i][x] + d[i][y]);
146         }
147         printf("%lld\n", ans);
148     }
149     return 0;
150 }

猜你喜欢

转载自www.cnblogs.com/wangwangyu/p/9693457.html