• 题解 AT1221 【水筒】


    题目链接

    Solution 水筒

    题目大意:一个(n imes m)的矩阵里有一些墙不能走,有一些建筑物,有一些地方是原野。每走过一格原野需要消耗一份水,建筑物可以将水壶补满。多次询问从一个建筑物到另一个建筑物水壶容量至少为多少。

    Kruskal重构树


    分析:

    首先不难想到暴力,我们把所有可以相互到达的建筑物两两连边,如果我们要使得最大边权尽量小那么我们就要求最小生成树。证明考虑贪心:不断加边直到两点连通,这就是Kruskal的过程。

    求树上两点间边权的最大值就是Kruskal重构树的板子题

    但是如果我们暴力枚举所有建筑物无法承受,但是我们发现有些边是没有用的,我们可以考虑类似于缩点的方法。我们给每个建筑物一个颜色,然后同一颜色的点离它最近的加油站都相同

    这样我们只需要枚举每个点以及和它相邻的点,如果颜色不同连边即可,这个可以在bfs的时候顺便计算,染色发现已经染过的不同色点就连边

    #include <cstdio>
    #include <vector>
    #include <queue>
    #include <utility>
    #include <algorithm>
    using namespace std;
    const int maxn = 2e3 + 100,maxp = 4e5 + 100,maxdep = 25;
    int n,m,p,q,vis[maxn][maxn],dis[maxn][maxn],deltax[] = {-1,0,1,0},deltay[] = {0,-1,0,1};
    namespace Graph{
    	struct Edge{int from,to,dist;};
    	vector<Edge> G[maxp];
    	inline void addedge(int from,int to,int dist){G[from].push_back(Edge{from,to,dist});}
    	int faz[maxp][maxdep + 1],dep[maxp],vis[maxp],col[maxp],val[maxp],col_tot;
    	inline void init(int u){
    		vis[u] = 1;col[u] = col_tot;
    		for(int i = 1;i <= maxdep;i++)
    			faz[u][i] = faz[faz[u][i - 1]][i - 1];
    		for(auto e : G[u]){
    			if(e.to == faz[u][0])continue;
    			faz[e.to][0] = u;
    			dep[e.to] = dep[u] + 1;
    			init(e.to);
    		}
    	}
    	inline void init(){
    		for(int i = (p << 1) - 1;i >= 1;i--)
    			if(!vis[i])dep[i] = 1,col_tot++,init(i);
    	}
    	inline int lca(int x,int y){
    		if(dep[x] < dep[y])swap(x,y);
    		for(int i = maxdep;i >= 0;i--)
    			if(dep[faz[x][i]] >= dep[y])
    				x = faz[x][i];
    		if(x == y)return x;
    		for(int i = maxdep;i >= 0;i--)
    			if(faz[x][i] != faz[y][i])
    				x = faz[x][i],y = faz[y][i];
    		return faz[x][0];
    	}
    	inline int query(int x,int y){return col[x] != col[y] ? -1 : val[lca(x,y)];}
    }
    namespace Kruskal{
    	using Graph::Edge;
    	vector<Edge> Edges;
    	inline void addedge(int from,int to,int dist){Edges.push_back(Edge{from,to,dist});}
    	int f[maxp],sz;
    	inline void init(){for(int i = 1;i <= p;i++)f[i] = i;sz = p;}
    	inline int find(int x){return x == f[x] ? x : f[x] = find(f[x]);}
    	inline void kruskal(){
    		sort(Edges.begin(),Edges.end(),[](const Edge &a,const Edge &b){return a.dist < b.dist;});
    		init();
    		int tot = p,lim = (p << 1) - 1;
    		for(int i = 1;i <= lim;i++)f[i] = i;
    		for(auto e : Edges){
    			int fx = find(e.from),fy = find(e.to);
    			if(fx != fy){
    				f[fx] = f[fy] = ++tot;
    				Graph::val[tot] = e.dist;
    				Graph::addedge(tot,fx,0),Graph::addedge(tot,fy,0);
    				if(tot == lim)break;
    			}
    		}
    	}
    }
    inline bool check(int x,int y){return x >= 1 && x <= n && y >= 1 && y <= m;}
    char mp[maxn][maxn];
    struct Pos{int x,y;}building[maxp];
    inline void bfs(){
    	queue<Pos> Q;
    	for(int i = 1;i <= p;i++)
    		Q.push(building[i]),vis[building[i].x][building[i].y] = i;
    	while(!Q.empty()){
    		Pos now = Q.front();Q.pop();
    		int x = now.x,y = now.y;
    		for(int i = 0;i < 4;i++){
    			int nx = x + deltax[i],ny = y + deltay[i];
    			if(!check(nx,ny) || mp[nx][ny] == '#' || vis[nx][ny] == vis[x][y])continue;
    			if(vis[nx][ny] && vis[x][y] != vis[nx][ny]){Kruskal::addedge(vis[x][y],vis[nx][ny],dis[x][y] + dis[nx][ny]);continue;}
    			vis[nx][ny] = vis[x][y];
    			dis[nx][ny] = dis[x][y] + 1;
    			Q.push(Pos{nx,ny});
    		}
    	}
    }
    int main(){
    	scanf("%d %d %d %d",&n,&m,&p,&q);
    	for(int i = 1;i <= n;i++)scanf("%s",mp[i] + 1);
    	for(int i = 1;i <= p;i++)scanf("%d %d",&building[i].x,&building[i].y);
    	bfs();
    	Kruskal::kruskal();
    	Graph::init();
    	for(int u,v,i = 1;i <= q;i++)
    		scanf("%d %d",&u,&v),printf("%d
    ",Graph::query(u,v));
    	return 0;
    } 
    
  • 相关阅读:
    【STM32F429】第5章 ThreadX NetXDUO网络协议栈介绍
    【STM32H7】第5章 ThreadX NetXDUO网络协议栈介绍
    【STM32F407】第5章 ThreadX NetXDUO网络协议栈介绍
    【STM32H7】第25章 ThreadX GUIX复选框Checkbox回调事件处理
    【STM32F429】第23章 ThreadX GUIX复选框Checkbox回调事件处理
    【STM32H7】第4章 初学ThreadX NetXDUO准备工作
    【STM32F429】第4章 初学ThreadX NetXDUO准备工作
    【STM32F407】第4章 初学ThreadX NetXDUO准备工作
    【STM32H7】第3章 PHY芯片和STM32的MAC基础知识
    【STM32F429】第3章 PHY芯片和STM32的MAC基础知识
  • 原文地址:https://www.cnblogs.com/colazcy/p/11825538.html
Copyright © 2020-2023  润新知