首页 > 编程语言 > 详细

E.Divide Square(树状数组/线段树)(扫描线)

时间:2020-08-26 17:29:20      阅读:91      评论:0      收藏:0      [点我收藏+]

题意:这里有一个\(10^6 \times 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 = 1e6 + 5;
struct Seg
{
    int y, x;
    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)
    {
        return x < rhs.x;
    }
}vline[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;
}

int query(int x)
{
    ll res = 0;
    for (int i = x; i; i -= lowbit(i)) res += c[i];
    return res;
}

int main() {
   
    const int q = 1e6;
    //水平,横
    int n, m;
    scanf("%d%d", &n, &m);

    ll res = 0;
    int num = 0;
    int y, x1, x2;
    for (int i = 1; i <= n; ++i)
    {
        scanf("%d%d%d", &y, &x1, &x2);
        if (x1 == 0 && x2 == q) ++res;
        seg[++num] = { y, x1, 1 };
        seg[++num] = { y, x2 + 1, -1 };
    }

    for (int i = 1; i <= m; ++i)
    {
        scanf("%d%d%d", &vline[i].x, &vline[i].y1, &vline[i].y2);
        if ((vline[i].y1 == 0) && (vline[i].y2 == q)) ++res;
    }

    sort(seg + 1, seg + num + 1);
    sort(vline + 1, vline + m + 1);

    for (int j = 0, i = 1; i <= m; ++i)
    {
        while (j < 2 * n && seg[j + 1].x <= vline[i].x)
        {
            ++j;
            modify(seg[j].y + 1, seg[j].k);
        }
        res += query(vline[i].y2 + 1) - query(vline[i].y1);
    }

    printf("%lld\n", res + 1);

    return 0;
}

E.Divide Square(树状数组/线段树)(扫描线)

原文:https://www.cnblogs.com/pixel-Teee/p/13566215.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!