扩散

题目大意

一个点每过一个单位时间就会向四个方向扩散一个距离,如图。扩散

两个点 a , b a,b a,b 连通,记作 e ( a , b ) e(a,b) e(a,b),当且仅当 a , b a,b a,b 的扩散区域有公共部分。

连通块的定义是块内的任意两个点 u , v u,v u,v 都必定存在路径 e ( u , a 0 ) , e ( a 0 , a 1 ) , … , e ( a k , v ) e(u,a0),e(a0,a1),…,e(ak,v) e(u,a0),e(a0,a1),…,e(ak,v)。

给定平面上的 n n n 给点,问最早什么时刻它们形成一个连通块。

对于 100 % 100\% 100% 的数据,满足 1 ≤ n ≤ 2000 , 1 ≤ X [ i ] , Y [ i ] ≤ 1 0 9 1≤n≤2000,1≤X[i],Y[i]≤10^9 1≤n≤2000,1≤X[i],Y[i]≤109。

解题思路

曼哈顿距离应该都懂的。

易得两个点联通,需要 ( ⌊ ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ 2 ⌋ ) + ( ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ )   m o d   2 ) (\left\lfloor\frac{|x_1-x_2|+|y_1-y_2|}{2}\right\rfloor) + (|x_1-x_2|+|y_1-y_2|)\bmod 2) (⌊2∣x1​−x2​∣+∣y1​−y2​∣​⌋)+(∣x1​−x2​∣+∣y1​−y2​∣)mod2) (前面算的是余数)。

故可设任意两点之间的距离为上面那个式子,跑一边最小生成树,求出最小生成树上最长的边,即为答案。

AC CODE

#include <bits/stdc++.h>

using namespace std;

#define int long long

#define _ 400007

int n;

int xx[_], yy[_];

int ans;

int tot;

struct abc
{
	int x, y, dis;
} e[4000007];

int fa[_];

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

bool cmp(abc a, abc b)
{
	return a.dis < b.dis;
}

void kruskal()
{
	sort(e + 1, e + tot + 1, cmp);
	for(int i = 1; i <= n; ++i) fa[i] = i;
	int kkk = 0;
	for(int i = 1; i <= tot; ++i)
	{
		int xx = find(e[i].x), yy = find(e[i].y);
		if(xx != yy)
		{
			fa[yy] = xx;
			kkk++;
			ans = max(ans, e[i].dis);
			if(kkk == n - 1) return;
		}
	}
}

signed main()
{
	cin >> n;
	for(int i = 1; i <= n; ++i)
	{
		cin >> xx[i] >> yy[i];
	}
	for(int i = 1; i <= n; ++i)
	{
		for(int j = 1; j < i; ++j)
		{
			int op = abs(xx[i] - xx[j]) + abs(yy[i] - yy[j]);
			e[++tot].x = i;
			e[tot].y = j;
			e[tot].dis = (op / 2) + (op & 1);
		}
	}
	kruskal(); 
	cout << ans << "\n";
	return 0;
}
上一篇:prim~(够5个了)


下一篇:BSGS && EXBSGS