CF 1051 F. The Shortest Statement

F. The Shortest Statement

http://codeforces.com/contest/1051/problem/F

 

题意:

  n个点,m条边的无向图,每次询问两点之间的最短路。(m-n<=20)

分析:

  dijkstra。

  如果是一棵树,那么可以直接通过,dis[u]+dis[v]-dis[lca]*2来求。现在如果建出一棵树,那么非树边只有小于等于21条。

  只经过树边的路径用上面的方式求出,考虑经过非树边的路径。

  经过非树边(至少一条),那么一定经过了这条边的顶点,所以可以对顶点做一次最短路,如果询问u,v经过这个顶点,那么就是dis[u]+dis[v]。

代码:

  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 #define fi(s) freopen(s,"r",stdin);
 12 #define fo(s) freopen(s,"w",stdout);
 13 using namespace std;
 14 typedef long long LL;
 15 
 16 inline int read() {
 17     int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
 18     for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
 19 }
 20 
 21 const LL INF = 1e18;
 22 const int N = 100005;
 23 
 24 int head[N], nxt[N << 1], to[N << 1], len[N << 1], En;
 25 int f[N][21], deth[N], tmp[100], tot;
 26 LL dis[N], d[50][N];
 27 int n, m;
 28 bool vis[N];
 29 
 30 void add_edge(int u,int v,int w) {
 31     ++En, to[En] = v, len[En] = w, nxt[En] = head[u], head[u] = En;
 32     ++En, to[En] = u, len[En] = w, nxt[En] = head[v], head[v] = En;
 33 }
 34 
 35 #define pa pair<LL,int>
 36 #define mp(a,b) make_pair(a,b)
 37 priority_queue< pa, vector< pa >, greater< pa > > q;
 38 
 39 void Dijkstra(int id,int S) {
 40     for (int i=1; i<=n; ++i) dis[i] = INF, vis[i] = false;
 41     dis[S] = 0;
 42     q.push(mp(0, S));
 43     while (!q.empty()) {
 44         int u = q.top().second; q.pop();
 45         if (vis[u]) continue;
 46         vis[u] = true;
 47         for (int i=head[u]; i; i=nxt[i]) {
 48             int v = to[i];
 49             if (dis[v] > dis[u] + len[i]) {
 50                 dis[v] = dis[u] + len[i];
 51                 q.push(mp(dis[v], v));
 52             }
 53         }
 54     }
 55     for (int i=1; i<=n; ++i) d[id][i] = dis[i];
 56 }
 57 void dfs(int u,int fa) {
 58     vis[u] = true;
 59     f[u][0] = fa;
 60     deth[u] = deth[fa] + 1;
 61     for (int i=head[u]; i; i=nxt[i]) {
 62         int v = to[i];
 63         if (v == fa) continue;
 64         if (vis[v]) tmp[++tot] = u, tmp[++tot] = v;
 65         else dis[v] = dis[u] + len[i], dfs(v, u);        
 66     }
 67 }
 68 int LCA(int u,int v) {
 69     if (deth[u] < deth[v]) swap(u, v);
 70     int d = deth[u] - deth[v];
 71     for (int i=20; i>=0; --i) 
 72         if (d & (1 << i)) u = f[u][i];
 73     if (u == v) return u;
 74     for (int i=20; i>=0; --i) 
 75         if (f[u][i] != f[v][i]) 
 76             u = f[u][i], v = f[v][i];
 77     return f[u][0];
 78 }
 79 int main() {    
 80     n = read(), m = read();
 81     for (int i=1; i<=m; ++i) {
 82         int u = read(), v = read(), w = read();
 83         add_edge(u, v, w);
 84     }
 85     
 86     dfs(1, 0);
 87     for (int i=1; i<=n; ++i) d[0][i] = dis[i];
 88     for (int j=1; j<=20; ++j) 
 89         for (int i=1; i<=n; ++i) f[i][j] = f[f[i][j-1]][j-1];
 90     sort(tmp + 1, tmp + tot + 1);
 91     int lim = tot; tot = 1;
 92     for (int i=2; i<=lim; ++i) if (tmp[tot] != tmp[i]) tmp[++tot] = tmp[i];    
 93     for (int i=1; i<=tot; ++i) Dijkstra(i, tmp[i]);
 94     
 95     int Q = read();
 96     while (Q --) {
 97         int u = read(), v = read();
 98         int t = LCA(u, v);
 99         LL ans = d[0][u] + d[0][v] - 2 * d[0][t];
100         for (int i=1; i<=tot; ++i) 
101             ans = min(ans, d[i][u] + d[i][v]);
102         printf("%I64d\n",ans);
103     }
104     return 0;
105 }

 

posted @ 2018-09-25 16:32  MJT12044  阅读(268)  评论(0编辑  收藏  举报