Codeforces 1041E. Divide Square 【扫描线】
题目链接
题目描述
在一个\(10^6\)x\(10^6\)的正方形中,给你n条垂直于y中的线和m条垂直于x轴的线,每一条线至少有一个端点和正方形相连。问最后这些组成的线构成了多少个新的小矩阵。
思路
考虑扫描线的思想,从左到右对平行于y轴的线的每个x进行扫描。
每个交点,必定形成一个新的矩形,对于范围为0~1000000的线来说,会额外增加一个区域,那么可以看成在矩形的初始状态就进行了额外的划分。答案就变成了初始所划分好的区域+所有交点数量。
先将所有水平的线段读入,根据扫描线的思想差分处理l和r+1,然后读入每条垂直的线。排序以后枚举每个x点,就相当于对于x点,求其上下界中点的数量,相当于一个差分以后的前缀和处理,同时每次更新一下整个上下区间的值即可。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
struct edge1 {
int x, y, d;
friend bool operator < (const edge1 a, const edge1 b) {
return a.x < b.x;
}
}a[N << 1];
struct edge2 {
int x, l, r;
friend bool operator < (const edge2 a, const edge2 b) {
return a.x < b.x;
}
}b[N << 1];
LL tr[N << 1];
int lowbit(int x) {
return x & -x;
}
void update(int x, int num) {
for(int i = x; i <= 1e6 + 2; i += lowbit(i)) tr[i] += num;
}
LL sum(int x) {
LL sum = 0;
for(int i = x; i > 0; i -= lowbit(i)) sum += tr[i];
return sum;
}
void solve() {
LL res = 1, idx = 0;
int n, m; cin >> n >> m;
for(int i = 1; i <= n; i++) {
int y, l, r; scanf("%d%d%d", &y, &l, &r);
if(l == 0 && r == 1e6) res++;
a[++idx] = {l, y, 1};
a[++idx] = {r + 1, y, -1};
}
for(int i = 1; i <= m; i++) {
int x, l, r; scanf("%d%d%d", &x, &l, &r);
if(l == 0 && r == 1e6) res++;
b[i] = {x, l, r};
}
sort(a + 1, a + 1 + idx);
sort(b + 1, b + 1 + m);
int pt1 = 1, pt2 = 1;
for(; pt1 <= idx && a[pt1].x == 0; pt1++) update(a[pt1].y, a[pt1].d);
for(int i = 1; i <= 1e6 + 10; i++) {
for(; pt1 <= idx && a[pt1].x == i; pt1++) {
update(a[pt1].y, a[pt1].d);
}
for(; pt2 <= m && b[pt2].x == i; pt2++) {
res += sum(b[pt2].r) - sum(b[pt2].l - 1);
}
}
printf("%lld\n", res);
}
int main() {
// freopen("in.txt", "r", stdin);
solve();
return 0;
}