LOJ3220「PA 2019」Terytoria【线段树,随机化】

给定 (X imes Y) 的球形网格(上下、左右边界分别连通)和 (n) 个边平行于坐标轴的矩形的两个对顶点,求这些矩形交的面积的最大值。

(nle 5cdot 10^5)(2le X,Yle 10^9)


矩形有四种情况:两维取区间/取补,所以两维独立,分别做然后把答案乘起来即可。

不容易发现,因为是选择一堆互补的区间交起来,所以只要选择一个点要求所有区间包含它就确定了决策,按顺序枚举这个点然后用线段树维护每个位置被包含的次数,若为 (n) 则属于区间交,时间复杂度 (O(nlog n))

当然也可以用随机权值,对每个区间异或上 ([0,2^{64})) 的自然数,众数的出现次数就是答案,时间复杂度 (O( ext{Sorting}(n))),错误概率同生日碰撞。

#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
using namespace std;
typedef unsigned long long LL;
typedef pair<int, LL> pii;
const int N = 1e6;
template<typename T>
void rd(T &x){
	int ch = getchar(); x = 0;
	for(;ch < '0' || ch > '9';ch = getchar());
	for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
template<typename T>
bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int n, X, Y, a[2][N];
pii b[N];
int work(int *a, int X){
	for(int i = 0;i < n;i += 2){
		LL v = (LL)rng()<<32|rng();
		b[i] = MP(a[i], v);
		b[i+1] = MP(a[i+1], v);
	}
	LL now = 0; sort(b, b+n);
	unordered_map<LL, int> ma;
	ma[0] = b[0].fi; b[n].fi = X;
	for(int i = 0;i < n;++ i){
		now ^= b[i].se; ma[now] += b[i+1].fi - b[i].fi;
	}
	int ans = 0;
	for(auto v : ma) chmax(ans, v.se);
	return ans;
}
int main(){
	rd(n); rd(X); rd(Y); n <<= 1;
	for(int i = 0;i < n;++ i)
		for(int j = 0;j < 2;++ j) rd(a[j][i]);
	printf("%lld
", (LL)work(a[0],X)*work(a[1],Y));
}
原文地址:https://www.cnblogs.com/AThousandMoons/p/14951496.html