BZOJ 4242 水壶
来源:互联网 发布:bdu 大数据 编辑:程序博客网 时间:2024/06/08 04:06
最小生成树+倍增
发现如果水壶是定值,那地图上肯定存在许多以建筑物为中心的联通块。并且随着水壶的增大,联通块大小也增大,有一些联通块会融合。
因此考虑把所有建筑物丢到队列搞BFS。如果两个联通块碰到了,就给这两个建筑物连上一条边。如果两个联通块代表的建筑之间已经存在一条路径可达,就不连。这样连出来是一棵树,而且也是最小生成树。
然而这样是错的,有一个反例,因为对于同一个距离,队列更新有先后顺序。先更新的点距离远,后更新的点可能先碰到先更新的点导致连边错误。然后我发现只要不管三七二十一,是边直接连就行了,然后再求最小生成树即可。边数至多
下午给自己的电脑装了ubuntu,用起来有点卡。。。好气
#include<cstdio>#include<algorithm>#define H 2005#define N 200005#define B 25using namespace std;namespace runzhe2000{ struct item{int x, y, belong, v;}que[H*H]; struct edge{int next, to, val;}e[N<<1]; struct pdge{int a, b, c;}pe[H*H]; bool operator < (pdge a, pdge b){return a.c < b.c;} char s[H][H]; int h, w, p, q, head, tail, ecnt, pecnt, f[N], fa[N][B], fv[N][B], last[N], bel[H][H], val[H][H], dep[N]; int dx[4] = {0,0,1,-1}, dy[4] = {1,-1,0,0}; int find(int x){return f[x] == x ? x : f[x] = find(f[x]);} void addedge(int a, int b, int c){e[++ecnt] = (edge){last[a], b, c}; last[a] = ecnt;} void addedge2(int a, int b, int c){addedge(a,b,c); addedge(b,a,c);} void addedge0(int a, int b, int c){pe[++pecnt] = (pdge){a,b,c};} void dfs(int x) { dep[x] = dep[fa[x][0]] + 1; for(int i = 1; i < B; i++) fa[x][i] = fa[fa[x][i-1]][i-1], fv[x][i] = max(fv[fa[x][i-1]][i-1], fv[x][i-1]); for(int i = last[x]; i; i = e[i].next) { int y = e[i].to; if(y != fa[x][0]) { fa[y][0] = x; fv[y][0] = e[i].val; dfs(y); } } } int ask_lca(int a, int b) { if(dep[a] < dep[b]) swap(a, b); for(int d = dep[a] - dep[b], i = 0; i < B; i++) if(d & (1<<i)) a = fa[a][i]; for(int i = B-1; ~i; i--) if(fa[a][i] != fa[b][i]) a = fa[a][i], b = fa[b][i]; return a == b ? a : fa[a][0]; } int ask_max(int b, int a) { int r = 0, d = dep[a] - dep[b]; for(int i = B-1; ~i; i--) if(d & (1<<i)) r = max(r, fv[a][i]), a = fa[a][i]; return r; } void main() { scanf("%d%d%d%d",&h,&w,&p,&q); for(int i = 1; i <= h; i++) scanf("%s",s[i]+1); for(int i = 1, x, y; i <= p; i++) { scanf("%d%d",&x,&y); que[tail++] = (item){x, y, i, 0}; bel[x][y] = i; } for(; head < tail; head++) { int x = que[head].x, y = que[head].y; for(int k = 0; k < 4; k++) { int nx = x + dx[k], ny = y + dy[k]; if(nx < 1 || ny < 1 || nx > h || ny > w || s[nx][ny] == '#') continue; if(bel[nx][ny] && bel[nx][ny] != bel[x][y]) addedge0(que[head].belong, bel[nx][ny], val[nx][ny] + que[head].v); else if(!bel[nx][ny]) { bel[nx][ny] = que[head].belong; val[nx][ny] = que[head].v + 1; que[tail++] = (item){nx, ny, bel[nx][ny], val[nx][ny]}; } } } sort(pe+1, pe+1+pecnt); for(int i = 1; i <= p; i++) f[i] = i; for(int i = 1; i <= pecnt; i++) { int f1 = find(pe[i].a), f2 = find(pe[i].b); if(f1 == f2) continue; f[f1] =f2; addedge2(pe[i].a,pe[i].b,pe[i].c); } for(int i = 1; i <= p; i++) if(!fa[i][0]) dfs(i); for(int i = 1, a, b; i <= q; i++) { scanf("%d%d",&a,&b); if(find(a) != find(b)) puts("-1"); else { int c = ask_lca(a, b), ans = 0; ans = max(ans, ask_max(c, a)); ans = max(ans, ask_max(c, b)); printf("%d\n",ans); } } } }int main(){ runzhe2000::main();}
0 0
- BZOJ 4242 水壶
- bzoj 4242: 水壶
- [网格最小生成树] BZOJ 4242 水壶
- 4242: 水壶
- bzoj 4242: 水壶 最小生成树&树上倍增
- 水壶
- bzoj4242: 水壶
- 水壶再一次爆了!!!
- 水壶、茶叶罐和我
- uva571 - Jugs(水壶)
- 用类去封装花瓶,水壶,对象
- 闷水壶的冒险码头
- POJ 3414 Pots(水壶)
- [bzoj4242][最小生成树]水壶
- <算法导论>第八章4 水壶(Kettle)
- 去除热水壶里的污垢
- 算法进化历程之“水壶问题”
- 满满一水壶的寻常事
- 奇怪的比赛 蓝桥杯
- 8VC Venture Cup 2017 - Elimination Round (先更A-B-C题)
- 关于栈的小思考
- 比特币或区块链相关的一些公司介绍
- 1083. List Grades (25)-排序(易)
- BZOJ 4242 水壶
- [初学python]编写冒泡排序
- Oracle查询优化-01单表查询
- STL 优先队列 定义 优先级
- 数据结构预备知识
- windows文件与Linux文件互转
- php分页和数据表字段设计注意事项
- 从发布者和订阅者来看事件
- 马士兵javaSE小项目chat和Tank单机版总结