CF391D2 Supercollider

lalaouye發表於2024-07-14

最小值最大考慮二分答案。

我們此時二分的答案為 \(X\),注意到每條線段如果被計入答案那麼肯定會對線段兩端座標有一定要求。我們先站在第一種 \(x=k\) 型別的線段進行考慮,如果這條線段能與另一種線段組合滿足答案,那麼另一種線段的 \(y\) 座標的值顯然必須滿足 \(y_i+X\le y_j\le y_i+l_i-X\)。但是這遠遠不夠,因為即使另一種線段的 \(y\) 座標滿足條件,在 \(x\) 座標中, \(x_i\) 必須也要滿足 \(x_j+X\le x_i\le x_j+l_j-X\)\(j\) 表示與當前豎直線段組合的線段下標。這樣有三維不能輕易用資料結構維護。然而我們發現每個橫著的線段只在一段範圍內能對豎直線段產生貢獻,於是我們離散化 \(x\) 座標,然後在 \(x_i\) 這裡插入豎直線段所需的 \(y\) 座標範圍,我們之後要在這裡詢問,並且在 \(x_j+X\) 這裡插入 \(y_j\),在 \(x_j+l_j-X\) 移除 \(y_j\),這樣我們就可以用線段樹維護這些操作了。

\(n\)\(m\) 同級,時間複雜度 \(\mathcal{O}(n\log{n}\log{V}+n\log^2V)\)

程式碼:

#include <bits/stdc++.h>
#define rep(i, l, r) for (int i = l; i <= r; ++ i)
#define rrp(i, l, r) for (int i = r; i >= l; -- i)
#define eb emplace_back
#define inf 1000000000
#define linf 100000000000000
#define pii pair <int, int>
using namespace std;
constexpr int N = 2e5 + 5, P = 1e9 + 7;
inline int rd ()
{
	int x = 0, f = 1;
	char ch = getchar ();
	while (! isdigit (ch)) { if (ch == '-') f = -1; ch = getchar (); }
	while (isdigit (ch)) { x = (x << 1) + (x << 3) + ch - 48; ch = getchar (); }
	return x * f;
}
int n, m;
class node
{
	public:
		int x, y, l;
	friend bool operator < (const node &a, const node &b)
	{
		return a.x < b.x;
	}
} c1[N], c2[N];
int li[N], len;
vector <int> v1[N], v2[N];
vector <pii> q[N];
int ls[N << 4], rs[N << 4], val[N << 4];
int rt, tot;
void upd (int &p, int l, int r, int x, int k)
{
	if (! p) p = ++ tot;
	if (l == r) return val[p] += k, void ();
	int mid = l + r >> 1;
	if (x <= mid) upd (ls[p], l, mid, x, k);
	else upd (rs[p], mid + 1, r, x, k);
	val[p] = val[ls[p]] + val[rs[p]];
}
int qry (int p, int l, int r, int L, int R)
{
	if (L > R) return 0;
	if (L <= l && r <= R) return val[p];
	int mid = l + r >> 1, ret = 0;
	if (L <= mid) ret += qry (ls[p], l, mid, L, R);
	if (R > mid) ret += qry (rs[p], mid + 1, r, L, R);
	return ret;
}
int check (int X)
{
	len = 0; 
	rep (i, 1, n) li[++ len] = c1[i].x;
	rep (i, 1, m) li[++ len] = c2[i].x + X, li[++ len] = c2[i].x + c2[i].l - X;
	sort (li + 1, li + len + 1);
	len = unique (li + 1, li + len + 1) - li - 1;
	rep (i, 1, n)
	{
		int x = lower_bound (li + 1, li + len + 1, c1[i].x) - li;
		q[x].eb (pii (c1[i].y + X, c1[i].y + c1[i].l - X));
	}
	rep (i, 1, m)
	{
		int x = lower_bound (li + 1, li + len + 1, c2[i].x + X) - li;
		int y = lower_bound (li + 1, li + len + 1, c2[i].x + c2[i].l - X) - li;
		if (x > y) continue; 
		v1[x].eb (c2[i].y);
		v2[y].eb (c2[i].y);
	}
	int chk = 0;
	rep (i, 1, len + 1)
	{
		for (auto v : v1[i]) upd (rt, -1e8, 2e8, v, 1);
		for (auto p : q[i]) chk |= qry (1, -1e8, 2e8, p.first, p.second);
		for (auto v : v2[i]) upd (rt, -1e8, 2e8, v, -1);
	}
	rep (i, 1, len + 1) v1[i].clear (), v2[i].clear (), q[i].clear ();
	return chk;
}
int main ()
{
	n = rd (), m = rd (); 
	rep (i, 1, n) c1[i].x = rd (), c1[i].y = rd (), c1[i].l = rd ();
	rep (i, 1, m) c2[i].x = rd (), c2[i].y = rd (), c2[i].l = rd ();
	sort (c1 + 1, c1 + n + 1);
	int l = 0, r = 2e8, ans = 0;
	while (l <= r)
	{
		int mid = l + r >> 1;
		if (check (mid))
		{
			l = mid + 1; ans = mid;
		} else r = mid - 1;
	}
	printf ("%d\n", ans);
}