题目:给一个n*m的方格,每个格子中间有个权值表示加上一堵墙的代价,然后需要构成一个图是的任意两点直接有且只有一条路,给出q组询问,每次查询两点之间的最短距离。
思路:最大生成树,求lca。很裸的一道题目,唉。但是比赛时没读懂题意,以为每次查询都对应着一个图。。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=500*500+10;
struct node{
int x,y;
ll w;
}s[maxn<<2];
ll w[505][505][2];
int n,m,cnt;
bool cmp(const node &a,const node&b)
{
return a.w>b.w;
}
vector<int>a[maxn];
int f[maxn][22],dep[maxn];
void dfs(int u,int fa)
{
for(int i=0;i<a[u].size();i++)
{
int v=a[u][i];
if(v==fa) continue;
f[v][0]=u;
dep[v]=dep[u]+1;
dfs(v,u);
}
}
int solve(int x,int y)
{
int ans=dep[x]+dep[y];
if(dep[x]<dep[y])
swap(x,y);
for(int i=20;i>=0;i--)
{
int k=f[x][i];
if(dep[k]>=dep[y])
x=k;
}
if(x!=y)
{
for(int i=20;i>=0;i--)
{
if(f[x][i]!=f[y][i])
{
x=f[x][i];
y=f[y][i];
}
}
x=f[x][0];
}
ans-=2*dep[x];
return ans;
}
int fa[maxn];
int getfa(int x)
{
return fa[x]==x?x:fa[x]=getfa(fa[x]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
char d[3],r[3];ll x,y;
scanf("%s%lld%s%lld",d,&x,r,&y);
w[i][j][0]=y;
w[i][j][1]=x;
}
}
cnt=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i!=n)
{
s[++cnt].x=(i-1)*m+j;
s[cnt].y=i*m+j;
s[cnt].w=w[i][j][1];
}
if(j!=m)
{
s[++cnt].x=(i-1)*m+j;
s[cnt].y=(i-1)*m+j+1;
s[cnt].w=w[i][j][0];
}
}
}
sort(s+1,s+cnt+1,cmp);
n=n*m;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=cnt;i++)
{
int x=s[i].x,y=s[i].y;
int fx=getfa(x),fy=getfa(y);
if(fx!=fy)
{
fa[fx]=fy;
a[x].push_back(y);
a[y].push_back(x);
}
}
dep[1]=1;
dfs(1,-1);
for(int j=1;j<=20;j++)
{
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
int q;
scanf("%d",&q);
while(q--)
{
int x,y,xx,yy;
scanf("%d%d%d%d",&x,&y,&xx,&yy);
x=(x-1)*m+y;
y=(xx-1)*m+yy;
int ans=solve(x,y);
printf("%d\n",ans);
}
return 0;
}