Codeforces Round #665 (Div. 2) E (扫描线)
传送门: Divide Square
思路:
不难发现分区数与线段的交点数有关(不包括与边界的交点)。初始时分区数为 1,每多 1 个交点,分区数就 +1,另外,每有一条横跨整个正方形的线,分区数也 +1。所以关键在于如何求出交点数,可以用扫描线处理,从下往上扫描,用树状数组维护扫描线与竖线的交点,遇到横线时查询对应区间上的交点数,累边进答案中
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef tuple<int, int, int> tup;
#define fsio ios::sync_with_stdio(false)
#define lowbit(x) ((x)&-(x))
const int inf = 0x3f3f3f3f;
const int maxn = 1e6+10;
struct node
{
int y, x1, x2, tp;
bool operator < (const node &b) const
{
if (y == b.y) return tp < b.tp;
return y < b.y;
}
}eg[maxn];
int c[maxn];
void update(int x, int k)
{
for (; x < maxn; x += lowbit(x)) c[x] += k;
}
int query(int x)
{
int ans = 0;
for (; x; x -= lowbit(x)) ans += c[x];
return ans;
}
int main()
{
int n, m;
while(cin>>n>>m)
{
int tot = 0;
ll ans = 0;
for (int i = 0; i < n; i++)
{
int y, x1, x2;
cin>>y>>x1>>x2;
if (y == 0 || y == 1e6) continue;
eg[tot++] = {y, x1, x2, 1};
if (x1 == 0 && x2 == 1e6) ans++;
}
for (int i = 0; i < m; i++)
{
int x, y1, y2;
cin>>x>>y1>>y2;
if (x == 0 || x == 1e6) continue;
eg[tot++] = {y1, x, 0, 0};
eg[tot++] = {y2, x, 0, 2};
if (y1 == 0 && y2 == 1e6) ans++;
}
memset(c, 0, sizeof(c));
sort(eg, eg+tot);
for (int i = 0; i < tot; i++)
{
if (eg[i].tp == 0) update(eg[i].x1, 1);
else if (eg[i].tp == 2) update(eg[i].x1, -1);
else
{
ans += query(eg[i].x2) - query(max(eg[i].x1-1, 0));
}
}
printf("%lld\n", ans+1);
}
return 0;
}