Gym

题目大意:给出一个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],mxd[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)mxd[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(mxd[fx]>mxd[fy])swap(fx,fy);
42         fa[fx]=fy,C[fx]=c,mxd[fy]=max(mxd[fy],mxd[fx]+1);
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 }
原文地址:https://www.cnblogs.com/asdfsag/p/11622902.html