首页 > 其他分享 >Solution - Hangar Hurdles

Solution - Hangar Hurdles

时间:2024-02-06 11:55:06浏览次数:23  
标签:dep Hurdles return int Solution fa ans Hangar dis

Link

感谢苏泊尔的题解,一点补充。

首先呢,可以处理出中心在每个格子 \((x, y)\) 上的最大边长 \(d_{x, y}\)。这个用一下二维前缀和统计 # 的个数再简单二分一下就好了,注意不能出界。

然后呢我们只能上下左右移动,考虑转化成一个图论问题(?)。所以就直接相邻的格子连边就好了,因为是双向边所以可以只连两个方向。那么边权自然就是两者 \(d\) 的最小值。这样的话,\((r_A, c_A) \to (r_B, c_B)\) 的路径上集装箱的最大尺寸就相当于走过的边的最小值。即答案就是 \((r_A, c_A) \to (r_B, c_B)\) 的路径上边的最小值的最大值,是一个最大瓶颈路。

当然 OI Wiki 给出的是最小瓶颈路,本质是一样的。具体怎么实现呢?

根据最小生成树定义,\(x\) 到 \(y\) 的最小瓶颈路上的最大边权等于最小生成树上 \(x\) 到 \(y\) 路径上的最大边权。

那么我们在跑 Kruskal 的时候,把选中的边新建成一棵树,\(x\) 到 \(y\) 的最小瓶颈路上的最大边权就相当于这棵树上 \(x \to y\) 路径的最大边权。这个很好维护,就是在维护 lca \(k\) 层父亲节点 \(fa_{u, k}\) 的基础上多维护一个 \(dis\),\(dis_{u, k}\) 表示从 \(u \to fa_{u, k}\) 的路径上的最大边权,拆成 \(u \to fa_{u, k - 1}\) 和 \(fa_{u, k - 1} \to fa_{u, k}\),转移就是 \(dis_{u, k} = \max(dis_{u, k - 1}, dis_{fa_{u, k - 1}, k - 1})\)。具体询问两点就是在跳 lca 的时候更新答案,应该比较 naive,可以直接看代码。

然后基本就做完了。注意可能有多个连通块所以要对每个没有访问过的点都 dfs 一遍。以及做的是最大瓶颈路所以反过来求最大生成树,然后转移改成 \(\min\) 啥的就好了。

很鲜:题目为啥保证是奇数呢,就是为了让它有中心,所以其实 $(x, y)$ 为中心的边长为 $2k + 1$ 覆盖的区域是 $(x - k, y - k)$ 到 $(x + k, y + k)$。二分 $k$ 就好了。
namespace liuzimingc {
const int N = 1e3 + 5, M = 2e6 + 5, K = 1e6 + 5;
#define endl '\n'

int n, q, s[N][N], d[N][N], m, fa[K], f[K][21], dis[K][21], dep[K];
bool vis[K];
char str[N][N];
vector<pair<int, int>> e[K];
struct node {
	int u, v, w;
} edge[M];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

int get_id(int x, int y) { return (x - 1) * n + y; }

int get(int x1, int y1, int x2, int y2) {
	return s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1];
}

void dfs(int u, int fa, int l) {
	if (vis[u]) return;
	vis[u] = true;
	dep[u] = dep[fa] + 1;
	f[u][0] = fa;
	dis[u][0] = l;
	for (int i = 1; i <= 20; i++) {
		f[u][i] = f[f[u][i - 1]][i - 1];
		dis[u][i] = min(dis[u][i - 1], dis[f[u][i - 1]][i - 1]);
	}
	for (const auto &i : e[u]) {
		int v = i.first, w = i.second;
		if (v == fa) continue;
		dfs(v, u, w);
	}
}

int lca(int x, int y) { // not actully works as it looks you know
	if (dep[x] > dep[y]) swap(x, y);
	int ans = 0x3f3f3f3f;
	for (int i = 20; ~i; i--)
		if (dep[f[y][i]] >= dep[x]) ans = min(ans, dis[y][i]), y = f[y][i];
	if (x == y) return ans;
	for (int i = 20; ~i; i--)
		if (f[x][i] != f[y][i]) ans = min(ans, min(dis[x][i], dis[y][i])), x = f[x][i], y = f[y][i];
	return min(ans, min(dis[x][0], dis[y][0]));
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr); cout.tie(nullptr);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> (str[i] + 1);
    for (int i = 1; i <= n; i++)
    	for (int j = 1; j <= n; j++)
    		s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + (str[i][j] == '#');
    for (int i = 1; i <= n; i++)
    	for (int j = 1; j <= n; j++) {
    		if (str[i][j] == '#') {
    			d[i][j] = -1;
    			continue;
			}
    		int l = 0, r = min({ i - 1, j - 1, n - i, n - j });
    		while (l < r) {
    			int mid = l + r + 1 >> 1;
    			if (get(i - mid, j - mid, i + mid, j + mid)) r = mid - 1;
    			else l = mid;
			}
			d[i][j] = l;
		}
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++) {
			if (i < n && ~min(d[i][j], d[i + 1][j])) edge[++m] = (node){ get_id(i, j), get_id(i + 1, j), min(d[i][j], d[i + 1][j]) };
			if (j < n && ~min(d[i][j], d[i][j + 1])) edge[++m] = (node){ get_id(i, j), get_id(i, j + 1), min(d[i][j], d[i][j + 1]) };
		} // 两个方向即可
	for (int i = 1; i <= n * n; i++) fa[i] = i;
	sort(edge + 1, edge + 1 + m, [](node a, node b){ return a.w > b.w; }); // 最大生成树
	for (int i = 1; i <= m; i++) {
		int x = find(edge[i].u), y = find(edge[i].v);
		if (x == y) continue;
		fa[x] = y;
		e[edge[i].u].push_back(make_pair(edge[i].v, edge[i].w));
		e[edge[i].v].push_back(make_pair(edge[i].u, edge[i].w));
	}
	for (int i = 1; i <= n * n; i++)
		if (!vis[i]) dfs(i, 0, 0); // 保证每个联通块都搜到
	cin >> q;
	while (q--) {
		int ra, ca, rb, cb;
		cin >> ra >> ca >> rb >> cb;
		if (find(get_id(ra, ca)) != find(get_id(rb, cb))) cout << 0 << endl; // 不连通
		else cout << 1 + 2 * lca(get_id(ra, ca), get_id(rb, cb)) << endl;
	} 
    return 0;
}
}  // namespace liuzimingc

标签:dep,Hurdles,return,int,Solution,fa,ans,Hangar,dis
From: https://www.cnblogs.com/liuzimingc/p/18009492/hangar

相关文章

  • Solution - Holes
    Link。暴力做是\(O(nm)\)的。怎么优化呢?I'venoslightestidea......
  • "resolutions" 主要用于解决依赖树中可能存在的版本冲突问题
    "resolutions":{"es6-iterator//es5-ext":"0.10.50","d//es5-ext":"0.10.50","es5-ext":"0.10.50"}这个是什么意思?这段配置是出现在package.json文件中的"resolutions"字段,它在使用Yarn2(berry)或......
  • 2.5闲话 & solution 『那是万物伊始的来途/或百川竞流的归处』
    哈哈哈我垫底了,为啥数据这么水啊哈哈我似乎发现很多人当OIer之前都没有一个稳定的网名solution-初三年前模拟测试3初三年前模拟测试3看沧海(桑田变幻)造多少(地覆天翻)似你我(进化简繁)该如何(才得一探)《普及难度》指T4动态开点李超线段树/凸壳又是一坨史,那场ABC是......
  • 2.4闲话 & solution - 『登陆宇宙/带着你所幻想的所有』
    \(\text{ARC}\)明天再改\(\text{solution}-『\textbf{AtCoderABC339}』\)比赛被骂的好惨QAQ,但是确实抽象,有点过于简单了,但凡看一眼F题和G题也不至于就过这几道题哈哈今天放ABC的改题来水闲话,不然我集训纪要就没得写了ABC339摘下头上紧箍的发带纠结的心散到九霄外提起......
  • 2.3 闲话 & solution - 『如蝶般地舞蹈哪会恐高』
    今天挺抽象的,上午一切正常,下午....先是因为明天\(1\)号楼锁宿舍楼断电断水所以搬宿舍到\(9\)号楼喵喵:去二楼,没电就去三楼然后去了二楼,没电没水啥也没有去三楼,没电没水啥也没有去四楼,有点有水其他奥赛去五楼才找到的合适位置,在\(9518\),快来找我玩?但是有宿管还是算了,也可能不......
  • 2.2 闲话 & solution - 『听,万物复苏的声音』
    一个好的闲话需要一张头图当然我还有一张solution-2024初三年前集训测试2\(189/400\),\(rk4\),还是太菜了,而且没打出来T3T4的暴力垫底了赛时似一捧细泉的奔逃跃过石缝岩脚降落到我怀抱待天地再静默一秒这蓬勃的心跳渴盼你能听到T1『上海』here和here天依......
  • Solution - Little Elephant and LCM & 之前学组合的一点疯话
    \(n\)个元素分成\(m\)份,每份不能为空,在\(n-1\)个空中插入\(m-1\)个板子,方案数\(C_{n-1}^{m-1}\)。为空则加上\(m\)个元素来垫着,就转化为上一个,然后就是\(C_{m-n+1}^{m-1}\)。所以为什么我之前不会插板?我是傻逼吗?然后突然发现,之前一直以为Gameswit......
  • Collision Resolution -Game Physics Engine Development总结
    ThevelocityofapointThevelocityofapointonanobjectdependsonbothitslinearandangularvelocity:\[\dot{q}=\dot{\theta}\times(q-p)+\dot{p}\qquad\qquad[1.0]\]where\(\dot{q}\)isthevelocityofthepoint,\(p\)ist......
  • Solution Set - 训练计划 链表
    咕掉了两道不可做题(指黑色)。梦幻布丁放在链表的题单里,和链表有什么关系呢???因为都是在对颜色整体进行操作,我们可以根据颜色拉出来对应的链表。那么每次合并就相当于把一个链表接到另一个链表上去,暴力修改,那么是\(O(n)\)的,但是要怎么维护答案呢?首先可以处理出不做任何操作时的......
  • Solution - Median Sum
    其它题不是很写得动了跑来写一下这个题,还是挺有趣的。给定由\(n\)个正整数\(a_1,a_2,\dots,a_n\)组成的可重集合,求出它的非空子集的和的中位数。设\(sum=\sum\limits_{i=1}^na_i\)。首先是对于任意一个子集,设其和为\(x\),我们将其取反,就是选的改成不选,不选的改......