Gym - 101173H Hangar Hurdles (kruskal重构树/最小生成树+LCA)
Posted asdfsag
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Gym - 101173H Hangar Hurdles (kruskal重构树/最小生成树+LCA)相关的知识,希望对你有一定的参考价值。
题目大意:给出一个n*n的矩阵,有一些点是障碍,给出Q组询问,每组询问求两点间能通过的最大正方形宽度。
首先需要求出以每个点(i,j)为中心的最大正方形宽度mxl[i][j],可以用二维前缀和+二分或者BFS求。
然后每相邻的两个点建一条权值为min(mxl[i][j],mxl[i‘][j‘])的边,求出整个图的最小生成树(注意边权要从大到小排序,实际上求出的是边权的“最大生成树”)或者kruskal重构树,对于每组询问(x1,y1),(x2,y2),答案为最小生成树上两点间路径的最小边权,或者kruskal重构树上两点LCA的权值。
如果建的是最小生成树,需要启发式合并(或者路径压缩,新开一个fa数组记录合并后的),如果建的是kruskal重构树,则需要弄个树剖或者倍增,加速求LCA的过程。
版本一(kruskal重构树+二维前缀和):
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1000+10; 4 char s[N][N]; 5 int n,a[N][N],mxl[N][N],m,Fa[N*N*2],Tot,Q,hd[N*N*2],ne,C[N*N*2]; 6 int fa[N*N*2],son[N*N*2],siz[N*N*2],dep[N*N*2],top[N*N*2]; 7 struct E {int v,nxt;} e[N*N*2]; 8 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 9 void dfs1(int u,int f,int d) { 10 fa[u]=f,son[u]=0,siz[u]=1,dep[u]=d; 11 for(int i=hd[u]; ~i; i=e[i].nxt) { 12 int v=e[i].v; 13 if(v==fa[u])continue; 14 dfs1(v,u,d+1),siz[u]+=siz[v]; 15 if(siz[v]>siz[son[u]])son[u]=v; 16 } 17 } 18 void dfs2(int u,int tp) { 19 top[u]=tp; 20 if(son[u])dfs2(son[u],top[u]); 21 for(int i=hd[u]; ~i; i=e[i].nxt) { 22 int v=e[i].v; 23 if(v==fa[u]||v==son[u])continue; 24 dfs2(v,v); 25 } 26 } 27 int lca(int u,int v) { 28 for(; top[u]!=top[v]; u=fa[top[u]]) 29 if(dep[top[u]]<dep[top[v]])swap(u,v); 30 if(dep[u]<dep[v])swap(u,v); 31 return v; 32 } 33 int sum(int x1,int y1,int x2,int y2) {return a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1];} 34 int ok(int i,int j,int x) {return !sum(i-x,j-x,i+x,j+x);} 35 int bi(int i,int j,int l,int r) { 36 int ret; 37 while(l<=r) { 38 int mid=(l+r)>>1; 39 if(ok(i,j,mid))l=mid+1,ret=mid; 40 else r=mid-1; 41 } 42 return ret; 43 } 44 struct E2 { 45 int x1,y1,x2,y2,c; 46 bool operator<(const E2& b)const {return c>b.c;} 47 } e2[N*N*2]; 48 int fd(int x) {return Fa[x]?Fa[x]=fd(Fa[x]):x;} 49 int id(int x,int y) {return (x-1)*n+(y-1)+1;} 50 void kruskal() { 51 sort(e2,e2+m); 52 Tot=n*n; 53 memset(hd,-1,sizeof hd),ne=0; 54 for(int i=1; i<=n; ++i) 55 for(int j=1; j<=n; ++j)C[id(i,j)]=mxl[i][j]; 56 for(int i=0; i<m; ++i) { 57 int x1=e2[i].x1,y1=e2[i].y1,x2=e2[i].x2,y2=e2[i].y2,c=e2[i].c; 58 int fx=fd(id(x1,y1)),fy=fd(id(x2,y2)); 59 if(fx==fy)continue; 60 int w=++Tot; 61 C[w]=c; 62 Fa[fx]=Fa[fy]=w; 63 addedge(w,fx),addedge(w,fy); 64 } 65 } 66 int main() { 67 scanf("%d",&n); 68 for(int i=1; i<=n; ++i)scanf("%s",s[i]+1); 69 for(int i=1; i<=n; ++i)for(int j=1; j<=n; ++j)a[i][j]=s[i][j]==‘#‘; 70 for(int i=1; i<=n; ++i) 71 for(int j=1; j<=n; ++j) 72 a[i][j]=a[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1]; 73 for(int i=1; i<=n; ++i) 74 for(int j=1; j<=n; ++j) 75 mxl[i][j]=s[i][j]==‘#‘?0:bi(i,j,0,min(min(i-1,n-i),min(j-1,n-j)))*2+1; 76 for(int i=1; i<=n; ++i) 77 for(int j=1; j<=n; ++j) { 78 if(i<n)e2[m++]= {i,j,i+1,j,min(mxl[i][j],mxl[i+1][j])}; 79 if(j<n)e2[m++]= {i,j,i,j+1,min(mxl[i][j],mxl[i][j+1])}; 80 } 81 kruskal(); 82 dfs1(Tot,0,1),dfs2(Tot,Tot); 83 scanf("%d",&Q); 84 while(Q--) { 85 int x1,y1,x2,y2; 86 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 87 printf("%d ",C[lca(id(x1,y1),id(x2,y2))]); 88 } 89 }
版本二(最小生成树+BFS):
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1000+10; 4 char s[N][N]; 5 int n,a[N][N],mxl[N][N],m,fa[N*N],Q,C[N*N],siz[N*N],dep[N*N]; 6 struct E { 7 int x1,y1,x2,y2,c; 8 bool operator<(const E& b)const {return c>b.c;} 9 } e[N*N*2]; 10 struct D {int x,y;}; 11 queue<D> q; 12 void upd(int x,int y,int c) {if(!~mxl[x][y])mxl[x][y]=c,q.push({x,y});} 13 void bfs() { 14 while(q.size())q.pop(); 15 memset(mxl,-1,sizeof mxl); 16 for(int i=0; i<=n+1; ++i) 17 for(int j=0; j<=n+1; ++j)if(i<1||i>n||j<1||j>n||s[i][j]==‘#‘)upd(i,j,0); 18 while(q.size()) { 19 int x=q.front().x,y=q.front().y; 20 q.pop(); 21 for(int x2=x-1; x2<=x+1; ++x2) 22 for(int y2=y-1; y2<=y+1; ++y2) { 23 if(x2<1||x2>n||y2<1||y2>n||~mxl[x2][y2])continue; 24 upd(x2,y2,mxl[x][y]+1); 25 } 26 } 27 for(int i=1; i<=n; ++i) 28 for(int j=1; j<=n; ++j)if(s[i][j]==‘.‘)mxl[i][j]=mxl[i][j]*2-1; 29 } 30 int fd(int x) {return fa[x]?fd(fa[x]):x;} 31 int id(int x,int y) {return (x-1)*n+(y-1)+1;} 32 int dfs(int u) {if(!fa[u])return 0; if(dep[u])return dep[u]; return dep[u]=dfs(fa[u])+1;} 33 void kruskal() { 34 sort(e,e+m); 35 for(int i=1; i<=n; ++i) 36 for(int j=1; j<=n; ++j)siz[id(i,j)]=1; 37 for(int i=0; i<m; ++i) { 38 int x1=e[i].x1,y1=e[i].y1,x2=e[i].x2,y2=e[i].y2,c=e[i].c; 39 int fx=fd(id(x1,y1)),fy=fd(id(x2,y2)); 40 if(fx==fy)continue; 41 if(siz[fx]>siz[fy])swap(fx,fy); 42 fa[fx]=fy,C[fx]=c,siz[fy]+=siz[fx]; 43 } 44 for(int i=1; i<=n; ++i) 45 for(int j=1; j<=n; ++j)dfs(id(i,j)); 46 } 47 int qry(int x1,int y1,int x2,int y2) { 48 int ret=min(mxl[x1][y1],mxl[x2][y2]); 49 int u=id(x1,y1),v=id(x2,y2); 50 while(u!=v) { 51 if(dep[u]<dep[v])swap(u,v); 52 ret=min(ret,C[u]); 53 u=fa[u]; 54 } 55 return ret; 56 } 57 int main() { 58 scanf("%d",&n); 59 for(int i=1; i<=n; ++i)scanf("%s",s[i]+1); 60 bfs(); 61 for(int i=1; i<=n; ++i) 62 for(int j=1; j<=n; ++j) { 63 if(i<n)e[m++]= {i,j,i+1,j,min(mxl[i][j],mxl[i+1][j])}; 64 if(j<n)e[m++]= {i,j,i,j+1,min(mxl[i][j],mxl[i][j+1])}; 65 } 66 kruskal(); 67 scanf("%d",&Q); 68 while(Q--) { 69 int x1,y1,x2,y2; 70 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 71 printf("%d ",qry(x1,y1,x2,y2)); 72 } 73 }
以上是关于Gym - 101173H Hangar Hurdles (kruskal重构树/最小生成树+LCA)的主要内容,如果未能解决你的问题,请参考以下文章