P11907 solution

· · 题解

思路

首先我们可以用 BFS 计算出每个点的「黑色恐怖距离」。

接下来考虑询问:每次求两点之间权值最小值的最大值,这让我们想到 Kruskal 重构树的性质:原图中两个点之间的所有简单路径上最小边权的最大值 = Kruskal 重构树上两点之间的 LCA 的权值,只是此处边变成了点。

于是直接建图再建一个类似于 Kruskal 重构树的树即可。

时间复杂度

## 代码 ```cpp #include<bits/stdc++.h> using namespace std; namespace Fastio{ #define read Fastio::readuint #define write Fastio::writeuint #define flush Fastio::clear #define SIZE (1<<23) #define NUMLEN 12 #define getchar() (_S==_T&&(_T=(_S=_in)+fread(_in,1,SIZE,stdin),_S==_T)?EOF:*_S++) char _in[SIZE],*_S=_in,*_T=_in; char _out[SIZE],*_P=_out; const char *_end=_out+SIZE; inline unsigned int readuint(){ unsigned int ret=0;char ch=getchar(); while(ch<'0'||ch>'9'){ch=getchar();} while(ch>='0'&&ch<='9'){ret=(ret<<1)+(ret<<3)+(ch^48);ch=getchar();} return ret; } inline void clear(){fwrite(_out,1,_P-_out,stdout);_P=_out;} inline void putchar(char ch){*(_P++)=ch;if(_P==_end)clear();} inline void outuint(unsigned int x){ if(x==0){putchar(48);return;} unsigned int i=0; char st[NUMLEN]; while(x) st[i++]=48^(x%10),x/=10; while(i--) putchar(st[i]); } inline void writeuint(int x,char ch){outuint(x);putchar(ch);} } const int N=200100,M=18; int n,m,l,tot,q,root,dis[N],stk[N],top=0,fa[N],dep[N],f[M][N],st[M][N]; tuple<int,int,int> place[N]; bool vis[N]; vector<int>e[N]; int ID(int i,int j,int k){return (i*m+j)*l+k;} int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} void merge(int u,int v){if(u!=(v=find(v))) e[fa[v]=u].push_back(v);} int lca(int u,int v){ if(dep[u]<dep[v]) swap(u,v); for(int i=M-1;~i;i--) if(dep[f[i][u]]>=dep[v]) u=f[i][u]; for(int i=M-1;~i;i--) if(f[i][u]!=f[i][v]) u=f[i][u],v=f[i][v]; if(u!=v) u=f[0][u]; return u; } int main(){ #ifdef LOCAL freopen("test.in","r",stdin); freopen("test.out","w",stdout); #endif n=read(),m=read(),l=read(),q=read(),tot=n*m*l; for(int i=0;i<n;i++) for(int j=0;j<m;j++) for(int k=0;k<l;k++) place[ID(i,j,k)]={i,j,k}; for(int i=0;i<tot;i++) dis[i]=-1; while(q--){ int i=read()-1,j=read()-1,k=read()-1; dis[stk[top++]=ID(i,j,k)]=0; } for(int I=0;I<top;I++){ int u=stk[I],v,i,j,k;tie(i,j,k)=place[u]; if(i&&!~dis[v=ID(i-1,j,k)]) dis[stk[top++]=v]=dis[u]+1; if(j&&!~dis[v=ID(i,j-1,k)]) dis[stk[top++]=v]=dis[u]+1; if(k&&!~dis[v=ID(i,j,k-1)]) dis[stk[top++]=v]=dis[u]+1; if(i+1-n&&!~dis[v=ID(i+1,j,k)]) dis[stk[top++]=v]=dis[u]+1; if(j+1-m&&!~dis[v=ID(i,j+1,k)]) dis[stk[top++]=v]=dis[u]+1; if(k+1-l&&!~dis[v=ID(i,j,k+1)]) dis[stk[top++]=v]=dis[u]+1; } for(int i=0;i<tot;i++) fa[i]=i; for(int I=top-1;~I;I--){ int u=stk[I],v,i,j,k;tie(i,j,k)=place[u];vis[u]=true; if(i&&vis[v=ID(i-1,j,k)]) merge(u,v); if(j&&vis[v=ID(i,j-1,k)]) merge(u,v); if(k&&vis[v=ID(i,j,k-1)]) merge(u,v); if(i+1-n&&vis[v=ID(i+1,j,k)]) merge(u,v); if(j+1-m&&vis[v=ID(i,j+1,k)]) merge(u,v); if(k+1-l&&vis[v=ID(i,j,k+1)]) merge(u,v); } f[0][stk[0]]=stk[0]; for(int I=0;I<top;I++){ int u=stk[I]; for(int v:e[u]) dep[v]=dep[u]+1,f[0][v]=u; } for(int j=1;j<M;j++) for(int i=0;i<tot;i++) f[j][i]=f[j-1][f[j-1][i]]; q=read(); while(q--){ int ui=read()-1,uj=read()-1,uk=read()-1; int vi=read()-1,vj=read()-1,vk=read()-1; write(dis[lca(ID(ui,uj,uk),ID(vi,vj,vk))],10); } flush(); return 0; } ```