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;
}
posted @ 2022-07-29 22:50  Pannta  阅读(98)  评论(0编辑  收藏  举报