1. 程式人生 > >ACM-ICPC 2018 徐州賽區網路預賽 J

ACM-ICPC 2018 徐州賽區網路預賽 J

題意: 在一個N*M的空地上,建牆造一個迷宮,使得迷宮的耗費最小,且迷宮中的任意兩點之間只有一條路,題目保證每組資料的迷宮唯一。 輸入迷宮中兩個點的座標,輸出兩點間的距離

思路:任意兩點間只有一條路,顯然是一棵樹。在地圖上建最大生成樹,就可以使得牆的耗費最小。兩點間距離就是在樹上跑LCA

#include <cstdio>
#include <queue>
#include <vector>
#include <cstring>
#include <algorithm>

using namespace std;

const
int maxn = (int)3e5 + 5; int N,M,Q; #define getpos(i,j) (i-1)*M + j struct Edge { int u,v,w; Edge(int _u=0,int _v=0,int _w=0) { u = _u; v = _v; w = _w; } bool operator<(const Edge a) const { return w > a.w; } }; vector<Edge> e; vector
<int>
G[maxn]; int f[maxn]; int Find(int x) { return x == f[x] ? x : f[x] = Find(f[x]); } int deep[maxn],in[maxn],out[maxn],cnt,anc[maxn][21],dis; void dfs(int u,int fa) { in[u] = ++cnt; deep[u] = deep[fa] + 1; anc[u][0] = fa; for (int i = 1; i <= 20; ++i) { anc[u][i] = anc[anc[u][i-1
]][i-1]; if(!anc[u][i]) break; } for(auto v:G[u]) { if(v!=fa) dfs(v,u); } out[u] = cnt; } int lca(int a,int b) { if(deep[a]>deep[b]) swap(a,b); if(in[a] <= in[b] && out[b] <= out[a]) return a; for(int i=20;~i;--i) if(deep[a] < deep[b] && deep[a] <= deep[anc[b][i]]) b = anc[b][i]; for(int i=20;~i;--i) if(anc[a][i]!=anc[b][i]) a = anc[a][i], b = anc[b][i]; return anc[a][0]; } void init() { cnt = 0; for (int i = 1; i < maxn; ++i) { f[i] = i; } deep[0] = 0; } int main() { init(); int u, v, w; char dir[2]; scanf("%d%d",&N,&M); for(int i = 1;i <= N; ++i) { for (int j = 1; j <= M ; ++j) { u = getpos(i,j); for (int k = 0; k < 2; ++k) { scanf("%s%d",dir,&w); if (dir[0] == 'D') v = getpos(i+1,j); else if (dir[0] == 'R') v = getpos(i,j+1); else continue; e.emplace_back(Edge(u,v,w)); } } } sort(e.begin(),e.end()); int x, y; for (auto i:e) { x = Find(i.u); y = Find(i.v); if(x!=y) { G[i.v].emplace_back(i.u); G[i.u].emplace_back(i.v); f[x] = y; } } dfs(getpos(1,1),0); scanf("%d",&Q); int x1, y1, x2, y2, L; while(Q--) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); u = getpos(x1,y1), v = getpos(x2,y2); L = lca(u,v); printf("%d\n",deep[u] + deep[v] - 2*deep[L]); } return 0; }