【BFS】【并查集】【Tarjan】【LCA】Gym

给你一张地图,给你q次询问,每次问你从A点到B点,最大能移动多大的箱子。

把每个点所能容纳的最大箱子求出来(BFS,八连通,一开始将所有边界点和障碍点入队)。然后从大到小排序。然后用并查集将相邻(四联通)的点依次链接起来,如果不路径压缩的话,那么两个节点的LCA的所能容纳的箱子大小就是答案。于是用并查集辅助建树,之后离线询问,然后Tarjan跑个LCA即可。

O(n^2+qlog(n)),log是因为map记录答案。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
using namespace std;
vector<int>ask[1010*1010];
int dx[]={0,1,0,-1,1,1,-1,-1},dy[]={1,0,-1,0,1,-1,1,-1};
int e,v[1010*1010],first[1010*1010],next[1010*1010];
void AddEdge(int U,int V){
	v[++e]=V;
	next[e]=first[U];
	first[U]=e;
}
struct Point{
	int x,y;
	Point(const int &x,const int &y){
		this->x=x;
		this->y=y;
	}
	Point(){}
};
bool operator < (const Point &a,const Point &b){
	return a.x!=b.x ? a.x<b.x : a.y<b.y;
}
map<Point,int>anss;
struct Node{
	Point p;
	int d;
	Node(const Point &p,const int &d){
		this->p=p;
		this->d=d;
	}
};
int n,siz[1010][1010],Siz[1010*1010],m,K;
int id[1010][1010];
bool cmp(const Point &a,const Point &b){
	return siz[a.x][a.y]>siz[b.x][b.y];
}
char a[1010][1010];
queue<Node>q;
bool vis[1010][1010];
Point ps[1010*1010];
int fa[1010*1010];
int find(int x){
	return x==fa[x] ? x : fa[x]=find(fa[x]);
}
Point qa[300010],qb[300010];
bool not_rt[1010*1010];
int ans[1010*1010];
bool VIS[1010*1010];
void LCA(int u)
{
	ans[u]=u;
	for(int i=first[u];i;i=next[i])
	  {
	  	LCA(v[i]);
	  	int f1=find(u),f2=find(v[i]);
	  	fa[f1]=f2;
        ans[find(u)]=u;
	  }
	VIS[u]=true;
	for(int i=0;i<ask[u].size();i++)
	  if(VIS[ask[u][i]]){
//	  	printf("%d %d %d %d
",min(u,ask[u][i]),max(u,ask[u][i]),ans[find(ask[u][i])],Siz[ans[find(ask[u][i])]]);
		anss[Point(min(u,ask[u][i]),max(u,ask[u][i]))]=Siz[ans[find(ask[u][i])]];
	  }
}
bool sb_q[300010];
int main(){
//	freopen("h.in","r",stdin);
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%s",a[i]+1);
	}
	for(int i=0;i<=n+1;++i){
		q.push(Node(Point(i,0),0));
		vis[i][0]=1;
		q.push(Node(Point(i,n+1),0));
		vis[i][n+1]=1;
	}
	for(int i=0;i<=n+1;++i){
		q.push(Node(Point(0,i),0));
		vis[0][i]=1;
		q.push(Node(Point(n+1,i),0));
		vis[n+1][i]=1;
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(a[i][j]=='#'){
				q.push(Node(Point(i,j),0));
				vis[i][j]=1;
			}
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			id[i][j]=++m;
		}
	}
	m=0;
	while(!q.empty()){
		Node U=q.front(); q.pop();
		int x=U.p.x,y=U.p.y;
		for(int i=0;i<8;++i){
			int tx=x+dx[i],ty=y+dy[i];
			if(tx>=1 && tx<=n && ty>=1 && ty<=n && !vis[tx][ty]){
				q.push(Node(Point(tx,ty),U.d+1));
				siz[tx][ty]=Siz[id[tx][ty]]=2*U.d+1;
				vis[tx][ty]=1;
			}
		}
	}
//	for(int i=1;i<=n;++i){
//		for(int j=1;j<=n;++j){
//			printf("%d ",siz[i][j]);
//		}
//		puts("");
//	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(siz[i][j]){
				ps[++m]=Point(i,j);
			}
		}
	}
	for(int i=1;i<=m;++i){
		fa[id[ps[i].x][ps[i].y]]=id[ps[i].x][ps[i].y];
	}
	sort(ps+1,ps+m+1,cmp);
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=m;++i){
		int x=ps[i].x,y=ps[i].y;
		for(int j=0;j<4;++j){
			int tx=x+dx[j],ty=y+dy[j];
			if(a[tx][ty]=='.' && vis[tx][ty]){
				int rt=find(id[tx][ty]);
				if(rt!=find(id[x][y])){
					AddEdge(id[x][y],rt);
//					printf("%d %d
",id[x][y],rt);
					not_rt[rt]=1;
					fa[rt]=id[x][y];
				}
			}
		}
		vis[x][y]=1;
	}
	scanf("%d",&K);
	for(int i=1;i<=K;++i){
		scanf("%d%d%d%d",&qa[i].x,&qa[i].y,&qb[i].x,&qb[i].y);
		int f1=find(id[qa[i].x][qa[i].y]),f2=find(id[qb[i].x][qb[i].y]);
		if(f1==f2){
			ask[id[qa[i].x][qa[i].y]].push_back(id[qb[i].x][qb[i].y]);
			ask[id[qb[i].x][qb[i].y]].push_back(id[qa[i].x][qa[i].y]);
		}
		else{
			sb_q[i]=1;
		}
	}
	for(int i=1;i<=m;++i){
		fa[id[ps[i].x][ps[i].y]]=id[ps[i].x][ps[i].y];
	}
	for(int i=1;i<=m;++i){
		if(!not_rt[id[ps[i].x][ps[i].y]]){
			LCA(id[ps[i].x][ps[i].y]);
		}
	}
	for(int i=1;i<=K;++i){
		if(sb_q[i]){
			puts("0");
		}
		else{
			printf("%d
",anss[Point(min(id[qa[i].x][qa[i].y],id[qb[i].x][qb[i].y]),
			max(id[qa[i].x][qa[i].y],id[qb[i].x][qb[i].y]))]);
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/7214356.html