bzoj4242: 水壶

题目
题解

Solution

很明显的一点,这道题目就是要在网格图上面计算一个最小生成树,然后就变成了货车运输一样的做法,可以倍增或者是克鲁斯卡尔重构树。
后面的部分就是原题,所以不再考虑,只考虑怎么样构造网格图最小生成树。
我们对于每一个可行的起点一起 b f s bfs ,对于每一个格子记录两个东西:一个记录距离当前位置最近的建筑的距离,以及是哪一个建筑。
当你bfsbfs到某个格子的时候,发现这个格子已经被其他建筑给标记过了,那么就可以直接从距离当前这个格子最近的建筑连向距离拓展出来的格子最近的那个建筑。
然而这题卡常,边数有 4 2000 2000 4∗2000∗2000 ,所以开一个 v e c t o r vector 记录所有可能的距离,然后把所有的距离全部挂在上面跑

Code

#include<bits/stdc++.h>
using namespace std;
const int N=200002,M=2002;
struct node{
	int x,y;
}a[N];
int bel[M][M],f[N<<1],fa[N<<1][18],dis[M][M],x,y,i,n,m,p,Q,dx[4]={1,-1,0,0},dy[4]={0,0,1,-1},cnt,ch[N<<1][2],dep[N<<1],w[N];
char s[M][M];
vector<node>E[M*M];
queue<node>q;
#define gc getchar
inline int rd(){
	int x=0,fl=1;char ch=gc();
	for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
	for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
	return x*fl;
}
inline void wri(int a){if(a<0)a=-a,putchar('-');if(a>=10)wri(a/10);putchar(a%10|48);}
inline void wln(int a){wri(a);puts("");}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
void bfs(){
	for (int i=1;i<=p;i++) q.push(a[i]),bel[a[i].x][a[i].y]=i;
	while (!q.empty()){
		node u=q.front();q.pop();
		for (int i=0;i<4;i++){
			node v=(node){u.x+dx[i],u.y+dy[i]};
			if (v.x<1 || v.x>n || v.y<1 || v.y>m || s[v.x][v.y]=='#') continue;
			if (!bel[v.x][v.y]){
				q.push(v);
				bel[v.x][v.y]=bel[u.x][u.y];
				dis[v.x][v.y]=dis[u.x][u.y]+1;
			}else E[dis[u.x][u.y]+dis[v.x][v.y]].push_back((node){bel[u.x][u.y],bel[v.x][v.y]});
		}
	}
}
void kruskal(){
	for (int i=1;i<=p;i++) f[i]=i;cnt=p;
	for (int i=0;i<=n*m;i++)
		for (int j=0;j<E[i].size();j++){
			int u=find(E[i][j].x),v=find(E[i][j].y);
			if (u==v) continue;
			cnt++;w[cnt]=i;
			ch[cnt][0]=u;ch[cnt][1]=v;
			f[u]=f[v]=f[cnt]=fa[u][0]=fa[v][0]=cnt;
		}
	for (int j=1;j<18;j++)
		for (int i=1;i<=cnt;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
}
int lca(int x,int y){
	if (dep[x]<dep[y]) swap(x,y);
	for (int i=17;~i;i--)
		if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
	if (x==y) return x;
	for (int i=17;~i;i--)
		if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
int main(){
	n=rd(),m=rd(),p=rd(),Q=rd();
	for (i=1;i<=n;i++) scanf("%s",s[i]+1);
	for (i=1;i<=p;i++) a[i].x=rd(),a[i].y=rd();
	bfs();kruskal();
	for (i=cnt;i>=p;i--) dep[ch[i][0]]=dep[ch[i][1]]=dep[i]+1;
	dep[0]=-1;
	for(;Q--;){
		x=rd(),y=rd();
		wln(find(x)==find(y)?w[lca(x,y)]:-1);
	}
}

猜你喜欢

转载自blog.csdn.net/xumingyang0/article/details/83623736