最小生成树Kruskal+LCA+bfs【bzoj4242】水壶
Description
JOI 君所居住的 IOI 市以一年四季都十分炎热著称。
IOI 市被分成 \(H\) 行,每行包含 \(W\) 块区域。每个区域都是建筑物、原野、墙壁之一。
IOI 市有 \(P\) 个区域是建筑物,坐标分别为 \((A_1, B_1)(A_2, B_2)\dots(A_P, B_P)\)。
JOI 君只能进入建筑物与原野,而且每次只能走到相邻的区域中,且不能移动到市外。JOI 君因为各种各样的事情,必须在各个建筑物之间往返。虽然建筑物中的冷气设备非常好,但原野上太阳非常毒辣,因此在原野上每走过一个区域都需要 1 升水。此外,原野上没有诸如自动售货机、饮水处之类的东西,因此 IOI 市的市民一般都携带水壶出行。大小为 \(x\) 的水壶最多可以装 \(x\) 升水,建筑物里有自来水可以将水壶装满。
由于携带大水壶是一件很困难的事情,因此 JOI 君决定携带尽量小的水壶移动。因此,为了随时能在建筑物之间移动,请你帮他写一个程序来计算最少需要多大的水壶。现在给出 IOI 市的地图和 \(Q\) 个询问,第 \(i\) 个询问包含两个整数 \(S_i, T_i\),对于每个询问,请输出:要从建筑物 \(S_i\)移动到 \(T_i\),至少需要多大的水壶?
Input
第一行四个空格分隔的整数 \(H,W,P,Q.\) 接下来 \(H\) 行,第 \(i\) 行有一个长度为 \(W\) 的字符串,每个字符都是
.或#之一,.表示这个位置是建筑物或原野,#表示这个位置是墙壁。 接下来 \(P\) 行描述 IOI 市每个建筑物的位置,第 \(i\) 行有两个空格分隔的整数 \(A_i\) 和 \(B_i\),表示第 \(i\) 个建筑物的位置在第 \(A_i\) 行第 \(B_i\) 列。保证这个位置在地图中是.。 接下来 \(Q\) 行,第 \(i\) 行有两个空格分隔的整数 \(S_i, T_i\)。Output
输出 \(Q\) 行,第 \(i\) 行一个整数,表示要从建筑物 \(S_i\) 移动到 \(T_i\),至少需要多大的水壶。 如果无法到达,输出
-1。如果不需要经过原野就能到达,输出0。
一道好题。货车运输的既视感.
难点在于建边,我们可以从建筑物向外扩展,这时候,如果扩展出来的地方相互接触,则可以直接对中心的建筑物之间直接建边即可.具体建边的话见我的大佬同桌王小呆的博客
建边出来跑\(Kruskal\),然后跑维护最大值的带权\(LCA\)即可。
代码
#include<cstdio> #include<cctype> #include<algorithm> #include<queue> #include<iostream> #define N 2008 #define R register using namespace std; inline void in(int &x) { int f=1;x=0;char s=getchar(); while(!isdigit(s)){if(s=='-')f=-1;s=getchar();} while(isdigit(s)){x=x*10+s-'0';s=getchar();} x*=f; } struct cod{int x,y;}; int n,m,P,Q; int res ,dis ; int vis ,fa[200008]; const int ax[]={0,0,-1,1}; const int ay[]={1,-1,0,0}; int head[4000018],tot,ttt,cnt; struct code{int u,v,w;}edge[5000018],e[5000018]; char s[N+2]; inline void add(int x,int y,int z) { e[++ttt].u=head[x]; e[ttt].v=y; e[ttt].w=z; head[x]=ttt; } inline bool ccp(const code&a,const code&b) { return a.w<b.w; } queue<cod>q; int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} inline int bfs() { while(!q.empty()) { int x=q.front().x,y=q.front().y; q.pop(); for(R int i=0;i<4;i++) { int nx=x+ax[i],ny=y+ay[i]; if(nx<1 or nx>n or ny>m or ny<1 or res[nx][ny])continue; if(dis[nx][ny]==-1) { vis[nx][ny]=vis[x][y]; dis[nx][ny]=dis[x][y]+1; q.push((cod){nx,ny}); } else if(vis[nx][ny]!=vis[x][y]) { edge[++tot].u=vis[nx][ny]; edge[tot].v=vis[x][y]; edge[tot].w=dis[x][y]+dis[nx][ny]; } } } } inline void kruskal() { sort(edge+1,edge+tot+1,ccp); for(R int i=1;i<=tot;i++) { R int u=edge[i].u,v=edge[i].v,w=edge[i].w; R int fu=find(u),fv=find(v); if(fu==fv)continue; fa[fu]=fv;add(fu,fv,w);add(fv,fu,w);cnt++; if(cnt==P-1)break; } } int gw[200008][21],f[200008][21],depth[400008]; void dfs(int u,int fa,int dis) { f[u][0]=fa;gw[u][0]=dis;depth[u]=depth[fa]+1; for(R int i=1;(1<<i)<=depth[u];i++) { f[u][i]=f[f[u][i-1]][i-1]; gw[u][i]=max(gw[u][i-1],gw[f[u][i-1]][i-1]); } for(R int i=head[u];i;i=e[i].u) { if(e[i].v==fa)continue; dfs(e[i].v,u,e[i].w); } } inline int lca(int x,int y) { int res=-2147483644; if(depth[x]>depth[y])swap(x,y); for(R int i=20;i>=0;i--) if(depth[x]+(1<<i)<=depth[y]) res=max(res,gw[y][i]),y=f[y][i]; if(x==y)return res; for(R int i=20;i>=0;i--) { if(f[x][i]==f[y][i])continue; res=max(res,max(gw[x][i],gw[y][i])); y=f[y][i],x=f[x][i]; } return max(res,max(gw[x][0],gw[y][0])); } int main() { in(n),in(m),in(P),in(Q); for(R int i=1;i<=n;i++) { scanf("%s",s+1); for(R int j=1;j<=m;j++) { res[i][j]= s[j]=='#'; dis[i][j]=-1; } } for(R int i=1,x,y;i<=P;i++) { in(x),in(y);fa[i]=i; dis[x][y]=0;vis[x][y]=i; q.push((cod){x,y}); } bfs(); kruskal(); for(R int i=1;i<=P;i++) if(!f[i][0])dfs(i,0,0); for(R int i=1,x,y;i<=Q;i++) { in(x),in(y); if(find(x)!=find(y))puts("-1"); else printf("%d\n",lca(x,y)); } }
- BZOJ4242:水壶(BFS & 最小生成树)
- 【bzoj4242】水壶 BFS+最小生成树+倍增LCA
- [最小生成树] [LCA] [BZOJ4242] 水壶(bottle)
- bzoj4242 水壶 最小生成树&树上倍增
- BZOJ 4242: 水壶 Kruskal+BFS
- [bzoj4242][最小生成树]水壶
- [网格最小生成树] BZOJ 4242 水壶
- BZOJ 1016 最小生成树计数 Kruskal
- [BZOJ1016][JSOI2008]最小生成树计数(Kruskal+计数)
- BZOJ3732 解析报告//LCA,最小生成树
- BZOJ 题目1016: [JSOI2008]最小生成树计数(Kruskal+Matrix_Tree)
- BZOJ 2429 聪明的猴子 (最小生成树 kruskal)
- BZOJ 1016: [JSOI2008]最小生成树计数 kruskal dfs
- 【BZOJ-2177】曼哈顿最小生成树 Kruskal + 树状数组
- bzoj3732 Network 最小生成树+LCA+树上倍增
- [BZOJ]3732: Network 最小生成树 LCA
- 【BZOJ2238】Mst 最小生成树+LCA+堆
- BZOJ.2177.曼哈顿最小生成树(Kruskal)
- 【Kruskal+dfs】BZOJ1016- [JSOI2008]最小生成树计数
- BZOJ 3732 Network —— 最小生成树 + 倍增LCA