题意:这里有一个(10^6 imes 10^6)的平面.你的任务是画一些线段在平面上,所有的线段都是水平的或者垂直的,至少有一侧是挨着平面的边线的.你的任务是数出有多少片被这些线段划分出来.
分析:,我们先把所有水平的线画出来,可以看到当红线继续穿过一根水平线的时候,平面数会增加一个.当然除了这种情况,如果不考虑相交产生的平面数,那么一根左端点是0,右端点是(10^6)的竖线也会增加一个平面.那么就只会有这两种情况会增加平面数.
我们可以枚举每根竖线,然后统计每根竖线和所有水平线的相交数,就是平面的增加数.这个我们可以使用扫描线,考虑一个水平线,它的左端点是它开始出现的点,右端点是它消失的点,我们可以使用树状数组维护,1表示增加,-1表示减少,一根扫描线的属性是[x, y, 1或者-1],一根水平线可以拆分成[x1, y, 1]和[x2, y + 1, -1],我们只要修改在树状数组上的y点即可,然后每次枚举一根竖线,我们把这根竖线x点之前的扫描线都读进来,然后查看在y1, y2之间的点数,即是相交的顶点数.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
using ll = long long;
const int N = 1000005;
struct Seg
{
int x, y;
int k;
bool operator<(const Seg& rhs)const
{
return x < rhs.x;
}
}seg[2 * N];
struct V
{
int x, y1, y2;
bool operator<(const V& rhs)const
{
return x < rhs.x;
}
}vlines[N];
ll c[N];
int lowbit(int x)
{
return x & (-x);
}
void modify(int x, int d)
{
for (int i = x; i < N; i += lowbit(i)) c[i] += d;
}
ll query(int x)
{
ll res = 0;
for (int i = x; i; i -= lowbit(i)) res += c[i];
return res;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
const int p = 1e6;
ll res = 0;
int num = 0;
int y, l, r;
for (int i = 1; i <= n; ++i)
{
scanf("%d%d%d", &y, &l, &r);
if (l == 0 && r == p) ++res;
seg[++num] = {l, y, 1};
seg[++num] = { r + 1, y, -1 };
}
for (int i = 1; i <= m; ++i)
{
scanf("%d%d%d", &vlines[i].x, &vlines[i].y1, &vlines[i].y2);
if (vlines[i].y1 == 0 && vlines[i].y2 == p) ++res;
}
sort(seg + 1, seg + num + 1);
sort(vlines + 1, vlines + m + 1);
for (int i = 1, j = 0; i <= m; ++i)
{
while (j < num && seg[j + 1].x <= vlines[i].x)
{
++j;
modify(seg[j].y + 1, seg[j].k);
}
res += query(vlines[i].y2 + 1) - query(vlines[i].y1);
}
printf("%lld
", res + 1);
return 0;
}