zoukankan      html  css  js  c++  java
  • E.Divide Square(树状数组/线段树)(扫描线)

    题意:这里有一个(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;
    }
    
  • 相关阅读:
    C# 通过反射初探ORM框架的实现原理
    Redis-Nosql数据库入门
    HTTPS 建立连接的详细过程
    Spring面试题
    struts2面试整理
    Java面试基本知识
    Spring MVC面试整理
    Mybatis面试整理
    Sublime 正则替换
    Hiberante知识点梳理
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13566215.html
Copyright © 2011-2022 走看看