题目:https://nanti.jisuanke.com/t/31462
赛后学长说最大生成树+LCA能过,我思考了下:
1.题目中要求求出最小的建墙方案,那么假设原来的格子和右边下边都有边,这不就是把相对小的边变成墙,反过来就是求最大生成树
2.既然有了最大生成树,那么在这个树上面来一发LCA就ok了
3.点数很大,不能用邻接矩阵存,建边最好就是用kruskal,prim建边有点蛋疼……
#include<cstring>
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define find fuck
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXN =300010;
const int DEG = 40;
bool vis[MAXN];
int lowc[MAXN];
struct Edge
{
int to,next;
} edge[MAXN*2];
struct E
{
int u,v,w;
}e[MAXN*2];
int head[MAXN],tot,tol;
void add(int u,int v,int w)
{
e[tol].u = u;
e[tol].v = v;
e[tol].w = w;
tol++;
}
void addedge(int u,int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
int f[MAXN];
int find(int v)
{
return f[v] == v ? v : f[v] = find(f[v]);
}
void init()
{
tot = 0;
tol = 0;
memset(head,-1,sizeof(head));
}
int fa[MAXN][DEG];//fa[i][j]表示结点i的第2^j个祖先
int deg[MAXN];//深度数组
bool flag[MAXN];
int dist[MAXN];
void BFS(int root)
{
queue<int>que;
deg[root] = 0;
fa[root][0] = root;
dist[root] = 0;
que.push(root);
while(!que.empty())
{
int tmp = que.front();
que.pop();
for(int i = 1; i < DEG; i++)
fa[tmp][i] = fa[fa[tmp][i-1]][i-1];
for(int i = head[tmp]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v == fa[tmp][0])
continue;
dist[v] = dist[tmp] +1;
deg[v] = deg[tmp] + 1;
fa[v][0] = tmp;
que.push(v);
}
}
}
int LCA(int u,int v)
{
if(deg[u] > deg[v])
swap(u,v);
int hu = deg[u], hv = deg[v];
int tu = u, tv = v;
for(int det = hv-hu, i = 0; det ; det>>=1, i++)
if(det&1)
tv = fa[tv][i];
if(tu == tv)
return tu;
for(int i = DEG-1; i >= 0; i--)
{
if(fa[tu][i] == fa[tv][i])
continue;
tu = fa[tu][i];
tv = fa[tv][i];
}
return fa[tu][0];
}
int n,m;
int id(int i,int j)
{
return i*m+j;
}
int main()
{
while(cin>>n>>m)
{
init();
for(int i = 0; i<n; i++)
{
for(int j = 0; j<m; j++)
{
f[id(i,j)] = id(i,j);
char a,b;
int x,y;
cin>>a>>x>>b>>y;
if(a != 'X')
{
add(id(i,j),id(i+1,j),x);
}
if(b != 'X')
{
add(id(i,j),id(i,j+1),y);
}
}
}
sort(e,e+tol,[&](const E &a,const E &b){return a.w > b.w;});
for(int i = 0;i<tol;i++)
{
int u = e[i].u;
int v = e[i].v;
int t1 = find(u);
int t2 = find(v);
if(t1 != t2)
{
f[t1] = t2;
//cout<<u<<' '<<v<<endl;
addedge(u,v);
addedge(v,u);
}
}
BFS(1);
int q;
cin>>q;
while(q--)
{
int a,b,c,d;
cin>>a>>b>>c>>d;
a--,b--,c--,d--;
int u = id(a,b);
int v = id(c,d);
cout<<dist[u] + dist[v] - 2*dist[LCA(u,v)]<<endl;
}
}
return 0;
}