CF1401E Divide Square

CF1401E Divide Square

容易发现所有边可以按是否与两边都相交分为两类。

对于普通边,和其他边相交产生的新矩形个数等于交点数。

对于贯穿边,和其他边相交产生的新矩形个数等于交点数 \(+1\)。因为贯穿了,所以自己本身就有切割的效果。

所以答案就是交点数 \(+\) 贯穿边数 \(+ 1\)

问题转化为如何快速求交点数,显然有一个 \(O(n^2)\) 的朴素做法。

优化很自然地想到扫描线,经典的对一维建树,对另一维扫描。注意到此处只需要单点修和区间查,所以树状数组就可以实现。

时间复杂度 \(O((n + m) \log 10^6)\)

解决本题的关键就是多画图,然后就能总结出结论。

#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
#define mp make_pair
#define fi first
#define se second
#define pii pair<int, int>
using namespace std;
using ll = long long;
const int N = 1500000;
const int MAXN = 1e6; 
struct node{
	int p, l, r; 
	bool operator < (const node &other)const{
		return p < other.p;
	}
}row[150000], col[150000];
vector<int> de[N], ad[N];
vector<pii> seg[N];
int n, m, sr = 0, sc = 0;
ll tr[N], ans = 0;
int lowbit(int x) {
	return x & -x;
}
void add(int x, int y){
	for(; x <= MAXN; x += lowbit(x)) tr[x] += y;
}
ll ask(int x){
	ll ret = 0;
	for(; x >= 1; x -= lowbit(x)) ret += tr[x];
	return ret;
}

signed main(){
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin >> n >> m;
	F(i, 1, n){ // shuiping
		int p, l, r;
		cin >> p >> l >> r;
		row[i] = (node){p, l, r};
		if(l == 0 && r == MAXN) ++ sr;
	} // chuizhi 
	F(i, 1, m){
		int p, l, r;
		cin >> p >> l >> r;
		col[i] = (node){p, l, r};
		if(l == 0 && r == MAXN) ++ sc;
	}
	F(i, 1, n){
		int p = row[i].p, l = row[i].l, r = row[i].r;
		if(l == 0 && r == MAXN) add(p, 1);
		else{
			if(l == 0){
				de[r].push_back(p);
				add(p, 1);
			}
			else{
				ad[l].push_back(p);
			}
		}
	}
	F(i, 1, m){
		seg[col[i].p].push_back(mp(col[i].l, col[i].r));
	}
	F(i, 0, MAXN){
		for(auto j : ad[i]) add(j, 1);
		for(auto j : seg[i]){
			if(j.fi == 0) ans += ask(j.se);
			else ans += (ask(j.se) - ask(j.fi - 1));
		}
		for(auto j : de[i]) add(j, -1);
	}
	cout << ans + sr + sc + 1 << '\n';
	return fflush(0), 0;
}
posted @ 2025-08-07 16:41  superl61  阅读(7)  评论(0)    收藏  举报