题解 想不出

传送门

没看见“有限区域”爆零了

首先这个 30 度很烦,我们转一下坐标系
就是原来的基向量乘上一个矩阵等于新的基向量,解出这个矩阵来即可

现在每个点可以向右/上引出一条射线,求最大有限区域数
考虑用欧拉公式转化一下
发现对于最终的每个连通块,每个有限区域的每条边唯一对应一条射线
那么我们要做的就是最大化这些射线的交点数
发现下图这样的东西一定不优
|
 ——
所以
image
那么可以枚举每个点为其定向
定向依据是其左上和右下的点数哪个多
最后欧拉公式算面数
于是可以做到 \(O(n\log n)\)
注意图中可以有不止一个连通块
hack 数据:

2
1 1
1 100

但我懒得处理了
所以只能做到 \(O(n^2)\) 吧,还不算并查集的复杂度
被沈老师 D 了
发现有连边的点形成二维偏序
所以一个思路是第一维用主席树,每个叶子节点再开一个线段树优化建图
这样是 \(O(n\log n)\) 的,但常数较大
于是又有一个常数更小的 \(O(n\log n)\) 做法是分治
还是处理二维偏序:对横坐标分治
将左右两边分别排序,若 \(y_{r_i}\leqslant y_{l_k}\)\(y_{r_j}\leqslant y_{l_k}\),则并查集合并 \(r_i, r_j\) 就可以了
复杂度 \(T(n)=O(n)+2T(\frac{n}{2})=O(n\log n)\),排序可以提前排好

一个有趣的问题:如果求所有区域(不要求有限)该怎么做呢?
答案是最大交点数 +1
考虑不旋转坐标系时,每个交点一定是一个区域内纵坐标最大的点
所以一个交点唯一对应一个平面

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define ll long long
// #define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n;
pair<int, int> p[N];

namespace task{
	#undef unix
	bool up[N];
	int sizx, sizy, m;
	double unix[N], uniy[N];
	pair<double, double> q[N];
	const double tr[2][2]={-0.5, 0.5,-sqrt(3)/6, -sqrt(3)/6};
	struct BIT1{
		int a[N];
		inline void upd(int i, int dat) {for (; i; i-=i&-i) a[i]+=dat;}
		inline int query(int i) {int ans=0; for (; i<=sizy; i+=i&-i) ans+=a[i]; return ans;}
		void clear() {memset(a, 0, sizeof(a));}
	}bit1;
	struct BIT2{
		int a[N];
		inline void upd(int i, int dat) {for (; i<=sizy; i+=i&-i) a[i]+=dat;}
		inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=a[i]; return ans;}
		void clear() {memset(a, 0, sizeof(a));}
	}bit2;
	void solve() {
		for (int i=1; i<=n; ++i) {
			unix[++sizx]=q[i].fir=p[i].fir*tr[0][0]+p[i].sec*tr[1][0];
			uniy[++sizy]=q[i].sec=p[i].fir*tr[0][1]+p[i].sec*tr[1][1];
		}
		sort(unix+1, unix+sizx+1); sort(uniy+1, uniy+sizy+1);
		sizx=unique(unix+1, unix+sizx+1)-unix-1;
		sizy=unique(uniy+1, uniy+sizy+1)-uniy-1;
		for (int i=1; i<=n; ++i) p[i]={lower_bound(unix+1, unix+sizx+1, q[i].fir)-unix, lower_bound(uniy+1, uniy+sizy+1, q[i].sec)-uniy};
		sort(p+1, p+n+1);
		for (int i=1; i<=n; ++i) bit2.upd(p[i].sec, 1);
		for (int i=1; i<=n; ++i) {
			bit2.upd(p[i].sec, -1);
			if (bit1.query(p[i].sec)>=bit2.query(p[i].sec)) up[i]=1;
			bit1.upd(p[i].sec, 1);
		}
		bit1.clear();
		for (int i=1; i<=n; ++i)
			if (up[i]) m+=bit1.query(p[i].sec);
			else bit1.upd(p[i].sec, 1);
		cout<<(m-n+1)<<endl;
	}
}

signed main()
{
	freopen("surface.in", "r", stdin);
	freopen("surface.out", "w", stdout);

	n=read();
	for (int i=1; i<=n; ++i) p[i].fir=read(), p[i].sec=read();
	task::solve();
	
	return 0;
}
posted @ 2022-03-08 19:34  Administrator-09  阅读(4)  评论(0编辑  收藏  举报