题意

一块 \(h ∗ w\) 的区域,存在障碍、空地、\(n\) 个建筑,从一个建筑到另一个建筑的花费为:路径上最长的连续空地的长度。

\(q\) 次询问:从建筑 \(s_i\) 到 \(t_i\) 的最小花费。

\(h, w \le 2 \times 10^3 ,n, q \le 2 \times 10^5\)

题解

对于任意两个建筑把它们之间的只走空地的最短路长度作为权值,然后做最小生成树。

如果搞出了最小生成树,那么就只需在 \(kruskal\) 重构树上求 \(LCA\) 就行了,因为 \(LCA\) 的权值是路上所有边的最大权值。

如果不会可以参考 「NOI2018」归程(Dijkstra + Kruskal重构树 + 倍增) 这题。

然而边数达到 \(O(n^2)\) ,暴力求边需要 \(O(n*h*w)\) 。

把所有建筑一起作为源点,跑 \(bfs\) ,可以得到离每个位置最近的建筑及距离。

然后,如果两个相邻位置的最近建筑不同,那么就将这对建筑连边,边数就降成 \(O(h * w)\) 的。

对于一个点如果存在多个最近的点,我们其实只需要把所有点连向第一个 \(bfs\) 到这个的点就行了,可以证明这是对的。(能自己画图理解)

所以最后复杂度就是 \(O(h * w \log (h * w) + q \log n)\)

总结

这种路径上 最大 / 最小 作为权值的题,常常可以考虑 \(kruskal\) 重构树来做。

平面上连边常常可以找特殊点来减少边数。

代码

/**************************************************************
Problem: 4242
User: DOFY
Language: C++
Result: Accepted
Time:32156 ms
Memory:271236 kb
****************************************************************/ #include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define fir first
#define sec second
#define mp make_pair using namespace std; typedef pair<int, int> PII; template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;} inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
} void File() {
#ifdef zjp_shadow
freopen ("4242.in", "r", stdin);
freopen ("4242.out", "w", stdout);
#endif
} const int Maxn = 2010, N = 4e5 + 1e3; bool G[Maxn][Maxn]; char str[Maxn]; queue<PII> Q; int id[Maxn][Maxn], dis[Maxn][Maxn]; struct Edge {
int u, v, w;
} lt[Maxn * Maxn * 4]; struct Cmp {
inline bool operator () (const Edge &lhs, const Edge &rhs) const {
return lhs.w < rhs.w;
}
}; int fa[N];
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
} int h, w, p, q; const int dir[4][2] = { {0, -1}, {0, 1}, {1, 0}, {-1, 0} }; int dep[N], val[N], anc[N][21], Log[N], Size; int Get_Dep(int u) {
if (!u || dep[u]) return dep[u];
return dep[u] = Get_Dep(anc[u][0]) + 1;
} int tot = 0;
void Build_Kruskal() {
For (i, 1, Size = p) fa[i] = i;
sort(lt + 1, lt + tot + 1, Cmp());
For (i, 1, tot) {
int u = find(lt[i].u), v = find(lt[i].v), w = lt[i].w;
if (u == v) continue ;
val[++ Size] = w;
fa[Size] =
anc[u][0] = fa[u] =
anc[v][0] = fa[v] = Size;
}
For (i, 1, Size) {
if (i > 1) Log[i] = Log[i >> 1] + 1;
dep[i] = Get_Dep(i);
}
For (j, 1, Log[Size]) For (i, 1, Size)
anc[i][j] = anc[anc[i][j - 1]][j - 1];
} inline int Calc(int u, int v) {
if (find(u) != find(v)) return -1;
if (dep[u] < dep[v]) swap(u, v);
int gap = dep[u] - dep[v];
For (i, 0, Log[gap]) if (gap >> i & 1) u = anc[u][i];
if (u == v) return val[u];
Fordown (i, Log[dep[u]], 0)
if (anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i];
return val[anc[u][0]];
} int main () { File(); h = read(), w = read(), p = read(), q = read(); For (i, 1, h) {
scanf ("%s", str + 1);
For (j, 1, w) G[i][j] = str[j] == '.';
} Set(dis, -1);
For (i, 1, p) {
int x = read(), y = read();
Q.push(mp(x, y)); id[x][y] = i; dis[x][y] = 0;
} while (!Q.empty()) {
PII u = Q.front(); Q.pop();
For (i, 0, 3) {
register int x = u.fir + dir[i][0], y = u.sec + dir[i][1];
if (!G[x][y]) continue ;
if (id[x][y]) {
if (id[x][y] != id[u.fir][u.sec])
lt[++ tot] = (Edge){id[x][y], id[u.fir][u.sec], dis[x][y] + dis[u.fir][u.sec]};
} else {
dis[x][y] = dis[u.fir][u.sec] + 1;
id[x][y] = id[u.fir][u.sec]; Q.push(mp(x, y));
}
}
} Build_Kruskal(); For (i, 1, q)
printf ("%d\n", Calc(read(), read())); return 0; }

BZOJ 4242: 水壶(Kruskal重构树 + Bfs)的更多相关文章

  1. BZOJ.4793.[CERC2016]Hangar Hurdles(Kruskal重构树 BFS)

    题目链接 \(Description\) 有一个\(n\times n\)的正方形网格,上面有若干障碍点.\(q\)次询问,每次询问把一个正方形箱子从\((x1,y1)\)推到\((x2,y2)\) ...

  2. 水壶-[Kruskal重构树] [解题报告]

    水壶 本来从不写针对某题的题解,但因为自己实在是太蠢了,这道题也神TM的恶心,于是就写篇博客纪念一下 H水壶 时间限制 : 50000 MS 空间限制 : 565536 KB 评测说明 : 2s,51 ...

  3. [bzoj 3732] Network (Kruskal重构树)

    kruskal重构树 Description 给你N个点的无向图 (1 <= N <= 15,000),记为:1-N. 图中有M条边 (1 <= M <= 30,000) ,第 ...

  4. BZOJ 4242: 水壶 Kruskal+BFS

    4242: 水壶 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 427  Solved: 112[Submit][Status][Discuss] D ...

  5. BZOJ 3732: Network Kruskal 重构树

    模板题,练练手~ Code: #include <cstdio> #include <algorithm> #define N 80000 #define setIO(s) f ...

  6. 【BZOJ 3732】 Network Kruskal重构树+倍增LCA

    Kruskal重构树裸题, Sunshine互测的A题就是Kruskal重构树,我通过互测了解到了这个神奇的东西... 理解起来应该没什么难度吧,但是我的Peaks连WA,,, 省选估计要滚粗了TwT ...

  7. BZOJ 3551: [ONTAK2010]Peaks加强版 [Kruskal重构树 dfs序 主席树]

    3551: [ONTAK2010]Peaks加强版 题意:带权图,多组询问与一个点通过边权\(\le lim\)的边连通的点中点权k大值,强制在线 PoPoQQQ大爷题解传送门 说一下感受: 容易发现 ...

  8. bzoj 3551 kruskal重构树dfs序上的主席树

    强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...

  9. 【BZOJ】3732: Network【Kruskal重构树】

    3732: Network Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2812  Solved: 1363[Submit][Status][Dis ...

随机推荐

  1. 无法从带有索引像素格式的图像创建graphics对象

    大家在用 .NET 做图片水印功能的时候, 很可能会遇到 “无法从带有索引像素格式的图像创建graphics对象”这个错误,对应的英文错误提示是“A Graphics object cannot be ...

  2. Django之admin中管理models中的表格

    Django之admin中管理models中的表格 django中使用admin管理models中的表格时,如何将表格注册到admin中呢? 具体操作就是在项目文件夹中的app文件夹中的admin中注 ...

  3. 单例模式及设计url分发

      1.单例模式 2.admin源码解析 3.注册源码流程图 3.admin之url方法的使用 4.admin源码之url设计 5.设计url源码流程 6.总结 1.单例模式 https://www. ...

  4. Day 4-3 os & sys模块

    常用方法: import os os.getcwd() # 获取当前程序的工作路径(python解释器的运行路径,不是脚本所在的路径.) os.listdir() # 获取当前程序根目录下的所有文件夹 ...

  5. RocketMQ消息队列安装

    一.官方安装文档 http://rocketmq.apache.org/docs/quick-start/ 下载地址 https://github.com/apache/rocketmq/releas ...

  6. 关于浏览器兼容问题——还有移动端meta问题

    <!DOCTYPE html><!--[if lt IE 7]> <html dir="ltr" lang="en-US" cla ...

  7. python设计模式第十九天【职责链模式】

    1.应用场景 (1)将一个任务拆分为具有顺序的多个部分,每个类完成相应的部分,并且顺序执行 (2)软件窗口的消息传播 (3)SERVLET容积的过滤器Filter的实现 2.代码实现 #!/usr/b ...

  8. python设计模式第十七天【解释器模式】

    1.应用场景 (1)解释预先定义的文法 2.代码实现 #!/usr/bin/env python #!_*_ coding:UTF-8 _*_ from abc import ABCMeta, abs ...

  9. python设计模式第八天【装饰器模式】

    1.定义 使用包装的释放扩展类的功能,但是不使用继承 2.使用场景 3.代码实现 #!/usr/bin/env python #! _*_ coding:UTF-8 _*_ def MyDecorat ...

  10. vue 響應接口

    全局方式: 增加屬性和set()和get(): vue.set(targname,key,vaule) targname:對象名或者數組名 key:字符串 value:任何值 刪除屬性和set()和g ...