首页 > 其他分享 >[ARC065E] へんなコンパス

[ARC065E] へんなコンパス

时间:2024-10-14 16:02:09浏览次数:1  
标签:return ARC065E int fa const find define

模拟赛题,简单题。

首先选择的两点之间距离永远不变,设为 \(d\)。

对于一个确定的点 \(x\),只要它能出现在一个对子里,其周围距离它为 \(d\) 的点都可以出现在对子里。

也就是我们只需要考虑每个点周围距离为 \(d\) 的点数量以及是否能到达。

暴力的思维是直接把四个平面拆开做 cdq,数据结构维护一下就行,\(O(n \log^2 n)\) 场上没写。

考虑智慧一点的思维,曼哈顿转切比雪夫,这样距离 \(x\) 为 \(d\) 的点是一个边长为 \(2d\),中心是 \(x\) 的正方形边上,那拆成两条横线和两条竖线即可。

需要的是区间求和以及合并点对,并查集+主席树维护即可,复杂度 \(O(n \log n)\)。

#include <bits/stdc++.h>
using namespace std;
#ifndef ONLINE_JUDGE
#include "Debug.h"
#else
#define debug(x...) 0
#define dbg(x...) 0
#endif

#define QwQ01AwA return 0
#define uint unsigned int
#define i64 long long
#define u64 unsigned long long
#define i128 __int128
#define file(x) freopen(x ".in", "r", stdin), freopen(x ".out", "w", stdout)
#define look_time cerr << 1.0 * clock() / CLOCKS_PER_SEC << '\n'
template <typename T> bool ckmax(T &x, const T y) {return x < y ? (x = y, 1) : 0;}
template <typename T> bool ckmin(T &x, const T y) {return y < x ? (x = y, 1) : 0;}

bool m1;
const int M = 1e7 + 5;
const int N = 1e5 + 5;
const int lim = 2e9;
int fa[N], ls[M], rs[M], cn, sum[M], head[M], val[M], nxt[M], cc;
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
void merge(int u, int v) {u = find(u), v = find(v); if (u == v) return ; fa[u] = v;}
void ins(int &p, const int &l, const int &r, const int &x, const int &id) {
	if (!p) p = ++cn, sum[cn] = 0;
	sum[p]++, val[++cc] = id, nxt[cc] = head[p], head[p] = cc;
	if (l == r) return ;
	int mid = (l + r) / 2;
	x <= mid ? ins(ls[p], l, mid, x, id) : ins(rs[p], mid + 1, r, x, id);
}
void clr(const int &p, const int &id) {int st = head[p]; while (head[p]) merge(id, val[head[p]]), head[p] = nxt[head[p]]; nxt[head[p] = st] = 0;}
int work(const int &p, const int &l, const int &r, const int &L, const int &R, const int &id) {
	if (!p) return 0;
	if (L <= l && r <= R) return clr(p, id), sum[p];
	int mid = (l + r) / 2, res = 0;
	if (L <= mid) res += work(ls[p], l, mid, L, R, id);
	if (mid < R) res += work(rs[p], mid + 1, r, L, R, id);
	return res;
}
struct Point {
	int x, y;
} p[N];
int n, S, T, D, w[N];
map < pair <int, int>, int> mp;
int mpx[N], mpy[N], tx, ty, rtx[N], rty[N];
bool m2;

signed main() {
	cerr << abs(&m2 - &m1) / 1024.0 / 1024 << '\n';
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n >> S >> T, cn = n;
	for (int i = 1; i <= n; i++) cin >> p[i].x >> p[i].y, fa[i] = i;
	D = abs(p[S].x - p[T].x) + abs(p[S].y - p[T].y);
	for (int i = 1; i <= n; i++) p[i] = {p[i].x + p[i].y, p[i].x - p[i].y}, mp[{p[i].x, p[i].y}] = 1, mpx[++tx] = p[i].x, mpy[++ty] = p[i].y;
	sort(mpx + 1, mpx + tx + 1), sort(mpy + 1, mpy + ty + 1);
	tx = unique(mpx + 1, mpx + tx + 1) - mpx - 1, ty = unique(mpy + 1, mpy + ty + 1) - mpy - 1;
	for (int i = 1; i <= n; i++) ins(rtx[lower_bound(mpx + 1, mpx + tx + 1, p[i].x) - mpx], 1, ty, lower_bound(mpy + 1, mpy + ty + 1, p[i].y) - mpy, i);
	for (int i = 1; i <= n; i++) ins(rty[lower_bound(mpy + 1, mpy + ty + 1, p[i].y) - mpy], 1, tx, lower_bound(mpx + 1, mpx + tx + 1, p[i].x) - mpx, i);
	for (int i = 1; i <= n; i++) {
		int lx, rx, ly, ry;
		lx = lower_bound(mpx + 1, mpx + tx + 1, max(-1ll * lim, 1ll * p[i].x - D)) - mpx;
		rx = upper_bound(mpx + 1, mpx + tx + 1, min(1ll * lim, 1ll * p[i].x + D)) - mpx - 1;
		ly = lower_bound(mpy + 1, mpy + ty + 1, max(-1ll * lim, 1ll * p[i].y - D)) - mpy;
		ry = upper_bound(mpy + 1, mpy + ty + 1, min(1ll * lim, 1ll * p[i].y + D)) - mpy - 1;
		if (p[i].x >= -lim + D && lx <= tx && mpx[lx] == p[i].x - D) w[i] += work(rtx[lx], 1, ty, ly, ry, i);
		if (p[i].x <= lim - D && rx >= 1 && mpx[rx] == p[i].x + D) w[i] += work(rtx[rx], 1, ty, ly, ry, i);
		if (p[i].y >= -lim + D && ly <= ty && mpy[ly] == p[i].y - D) w[i] += work(rty[ly], 1, tx, lx, rx, i);
		if (p[i].y <= lim - D && ry >= 1 && mpy[ry] == p[i].y + D) w[i] += work(rty[ry], 1, tx, lx, rx, i);
		if (mp.count({p[i].x - D, p[i].y - D})) w[i]--;
		if (mp.count({p[i].x - D, p[i].y + D})) w[i]--;
		if (mp.count({p[i].x + D, p[i].y - D})) w[i]--;
		if (mp.count({p[i].x + D, p[i].y + D})) w[i]--;
	}
	assert(find(S) == find(T));
	i64 ans = 0;
	for (int i = 1; i <= n; i++) if (find(i) == find(S)) ans += w[i];
	assert(ans % 2 == 0);
	cout << ans / 2 << '\n';
	look_time;
	QwQ01AwA;
}
/*
g++ -o sol sol.cpp -O2 -Wall -Wextra -Wl,--stack=536870912 -D LOCAL -D_GLIBCXX_ASSERTIONS
*/

标签:return,ARC065E,int,fa,const,find,define
From: https://www.cnblogs.com/Anonymely/p/18464385

相关文章