[网格最小生成树] BZOJ 4242 水壶
来源:互联网 发布:手机数据开了不能用 编辑:程序博客网 时间:2024/04/28 23:13
平面网格上的最小生成树
还可以这么做 Orz
bfs一遍
注意到是平面图,因此考虑用bfs求最小生成树。直接以每个建筑为原点拓展显然不行,那么我们可以把每个建筑都加入队列一起拓展,那么对于一个点,一定会被其中的一个建筑第一次拓展到,则令这个点为该建筑的“势力范围”。那么对于两个建筑“势力范围”边界上接触的点,显然这两个建筑之间的边只能有边界上的点得到。因此就用这些点连边即可。显然这样得到是最小生成树。
发现一个小trick
在并查集合并的时候按大小合并同时控制父亲节点这样就可以把生成树的高度控制在
#include<cstdio>#include<cstdlib>#include<algorithm>#include<vector>using namespace std;typedef pair<int,int> abcd;inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; } return *p1++;}inline void read(int &x){ char c=nc(),b=1; for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}inline void read(char *x){ char c=nc(); int len=0; for (;!(c=='.' || c=='#');c=nc()); for (;c=='.' || c=='#';x[++len]=c,c=nc()); x[++len]=0;}const int N=2005;const int M=200005;int n,m,P,T;char Map[2005][2005];vector<abcd> stk[N*N];int l,r;abcd Q[N*N],val[N][N];const int dx[]={0,0,1,-1};const int dy[]={1,-1,0,0};inline void BFS(){ while (l<r) { ++l; int x=Q[l].first,y=Q[l].second; for (int k=0;k<4;k++) { int sx=x+dx[k],sy=y+dy[k]; if (sx<=0 || sy<=0 || sx>n || sy>m || Map[sx][sy]=='#') continue; if (val[sx][sy]==abcd(0,0)) val[sx][sy]=abcd(val[x][y].first+1,val[x][y].second),Q[++r]=abcd(sx,sy); else if (val[x][y].second!=val[sx][sy].second) stk[val[x][y].first+val[sx][sy].first].push_back(abcd(val[x][y].second,val[sx][sy].second)); } }}struct edge{ int u,v,w; int next;};edge G[M<<1];int head[M],inum;inline void add(int u,int v,int w,int p){ G[p].u=u; G[p].v=v; G[p].w=w; G[p].next=head[u]; head[u]=p;}int fat[M][21],dis[M][21],depth[M];namespace UQS{ int fat[M],rank[M]; inline void init(int n){ for (int i=1;i<=n;i++) fat[i]=i; } inline int Fat(int u){ return u==fat[u]?u:fat[u]=Fat(fat[u]); } inline bool Union(int x,int y){ x=Fat(x),y=Fat(y); if (x==y) return 0; if (rank[x]>rank[y]) swap(x,y); if (rank[x]==rank[y]) rank[y]++; fat[x]=y; return 1; }}inline void Kru(){ using namespace UQS; init(P); for (int i=0;i<=n*m;i++) for (int j=0;j<(signed)stk[i].size();j++) if (Union(stk[i][j].first,stk[i][j].second)) add(stk[i][j].first,stk[i][j].second,i,++inum),add(stk[i][j].second,stk[i][j].first,i,++inum);}#define V G[p].vinline void dfs(int u,int fa){ fat[u][0]=fa; depth[u]=depth[fa]+1; for (int k=1;k<=20;k++) { fat[u][k]=fat[fat[u][k-1]][k-1]; dis[u][k]=max(dis[u][k-1],dis[fat[u][k-1]][k-1]); } for (int p=head[u];p;p=G[p].next) if (V!=fa) dis[V][0]=G[p].w,dfs(V,u);}inline int Query(int u,int v){ if (UQS::Fat(u)!=UQS::Fat(v)) return -1; int ret=0; if (depth[u]<depth[v]) swap(u,v); for (int k=20;~k;k--) if (((depth[u]-depth[v])>>k)&1) ret=max(ret,dis[u][k]),u=fat[u][k]; if (u==v) return ret; for (int k=20;~k;k--) if (fat[u][k]!=fat[v][k]) { ret=max(ret,dis[u][k]); ret=max(ret,dis[v][k]); u=fat[u][k],v=fat[v][k]; } return max(ret,max(dis[v][0],dis[u][0]));}int main(){ int x,y; freopen("t.in","r",stdin); freopen("t.out","w",stdout); read(n); read(m); read(P); read(T); for (int i=1;i<=n;i++) read(Map[i]); for (int i=1;i<=P;i++) read(x),read(y),val[x][y]=abcd(0,i),Q[++r]=abcd(x,y); BFS(); Kru(); for (int i=1;i<=P;i++) if (!depth[i]) dfs(i,0); while (T--) { read(x); read(y); printf("%d\n",Query(x,y)); } return 0;}
0 0
- [网格最小生成树] BZOJ 4242 水壶
- bzoj 4242: 水壶 最小生成树&树上倍增
- [bzoj4242][最小生成树]水壶
- [最小生成树] [LCA] [BZOJ4242] 水壶(bottle)
- BZOJ 4242 水壶
- bzoj 4242: 水壶
- bzoj 2561: 最小生成树
- BZOJ 1050 最小生成树
- bzoj 1232 最小生成树
- bzoj 2561: 最小生成树
- BZOJ 2561 最小生成树 最小割
- BZOJ 2561 - 最小生成树 + 最小割
- 【BZOJ 2561】最小生成树 最小割
- BZOJ 2561(最小生成树-最小割)
- [BZOJ]2561 最小生成树 最小割
- BZOJ 2561: 最小生成树 最小割
- 4242: 水壶
- BZoj 1016: [JSOI2008]最小生成树计数【最小生成树】
- [DP Euler Zigzag Number] BZOJ 1925 [Sdoi2010]地精部落
- [组合数学] BZOJ 2467 [中山市选2010]生成树
- [高斯消元 线性基 生成树 随机化权值Xor] BZOJ 3569 DZY Loves Chinese II
- [分治] BZOJ 3745 [Coci2015]Norma
- Android Service基础
- [网格最小生成树] BZOJ 4242 水壶
- WEEK3-HOMEWORK
- git操作
- 使用hibernate注解以及几个简单语句
- 常见的问题总结
- 如何查看某个端口被谁占用
- django+js+ajax刷新页面
- windows wdk 目录简介
- 算法——排序/查找