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;
}

浙公网安备 33010602011771号