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 }

原文地址:https://www.cnblogs.com/wangwangyu/p/9693457.html

时间: 2024-08-01 20:53:55

Educational Codeforces Round 51 (Rated for Div. 2) The Shortest Statement的相关文章

Educational Codeforces Round 36 (Rated for Div. 2)

Educational Codeforces Round 36 (Rated for Div. 2) F. Imbalance Value of a Tree You are given a tree T consisting of n vertices. A number is written on each vertex; the number written on vertex i is ai. Let's denote the function I(x,?y) as the differ

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars There are n pillars aligned in a row and numbered from 1 to n. Initially each pillar contains exactly one disk. The i-th pillar contains a disk having radius ai. You can move these disks

Educational Codeforces Round 71 (Rated for Div. 2) D - Number Of Permutations

原文链接:https://www.cnblogs.com/xwl3109377858/p/11405773.html Educational Codeforces Round 71 (Rated for Div. 2) D - Number Of Permutations You are given a sequence of n pairs of integers: (a1,b1),(a2,b2),…,(an,bn). This sequence is called bad if it is

Educational Codeforces Round 36 (Rated for Div. 2) 题解

Educational Codeforces Round 36 (Rated for Div. 2) 题目的质量很不错(不看题解做不出来,笑 Codeforces 920C 题意 给定一个\(1\)到\(n\)组成的数组,只可以交换某些相邻的位置,问是否可以将数组调整为升序的 解题思路 首先如果每个数都能通过交换到它应该到的位置,那么就可以调整为升序的. 但实际上交换是对称的,如果应该在的位置在当前位置前方的数都交换完成,那么整体就是排好序的,因为不可能所有不在相应位置的数都在相应位置的后方.

Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes

Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes 题目连接: http://codeforces.com/contest/985/problem/E Description Mishka received a gift of multicolored pencils for his birthday! Unfortunately he lives in a monochrome w

Educational Codeforces Round 55 (Rated for Div. 2)

Educational Codeforces Round 55 (Rated for Div. 2) 链接 A Vasya and Book 傻逼题..注意判边界. #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<map> #include<vector> #include<cm

Educational Codeforces Round 57 (Rated for Div. 2)

get人生第二场CF! 成绩:(exACM) rank858 AC3/7 Penalty57 rating1648(+52) 题目:Educational Codeforces Round 57 (Rated for Div. 2) 错题题解: D. Easy Problem E. The Top Scorer F. Inversion Expectation G. Lucky Tickets 原文地址:https://www.cnblogs.com/xht37/p/10198321.html

Educational Codeforces Round 58 (Rated for Div. 2)(待更新)

get人生第七场CF! 成绩:(exACM) rank AC3/7 Penalty104 rating() 题目:Educational Codeforces Round 58 (Rated for Div. 2) 错题题解: C. Division and Union 原文地址:https://www.cnblogs.com/xht37/p/10260260.html

Educational Codeforces Round 59 (Rated for Div. 2) DE题解

Educational Codeforces Round 59 (Rated for Div. 2) D. Compression 题目链接:https://codeforces.com/contest/1107/problem/D 题意: 给出一个n*(n/4)的矩阵,这个矩阵原本是一些01矩阵,但是现在四个四个储存进二进制里面,现在给出的矩阵为0~9以及A~F,表示0~15. 然后问这个矩阵能否压缩为一个(n/x)*(n/x)的矩阵,满足原矩阵中大小为x*x的子矩阵所有数都相等(所有子矩阵构