Overlapping Rectangles 离散+线段树 +扫描线

首先看

unique的作用是“去掉”容器中相邻元素的重复元素(不一定要求数组有序),它会把重复的元素添加到容器末尾(所以数组大小并没有改变),而返回值是去重之后的尾地址(转自https://www.cnblogs.com/hua-dong/p/7943983.html)

之后看离散 https://blog.csdn.net/xiangaccepted/article/details/73276826

之后看https://blog.csdn.net/qq_18661257/article/details/47658191

这道题目说明一下,pushup(rt, l, r)的作用以及其中判断的来由。

  1. void pushup(int rt,int l,int r) {  
  2.     if (Col[rt]) Sum[rt] = X[r+1] - X[l];//利用[ , ),这个区间性质,左闭右开  
  3.     else if (l == r) Sum[rt] = 0;  
  4.     else Sum[rt] = Sum[rt<<1] + Sum[rt<<1|1];  
  5. }  
如果当前的位置为叶子节点,Col[rt] == 1话证明被完全覆盖了,进行赋值(这里涉及到了离散化,建议读者可以学习离散化的知识),如果为Col[rt] == 0,这个叶子节点一定为0

如果当前位置不是叶子节点那么我们就要小心一点了,Col[rt] == 1话证明被完全覆盖了,如果Col[rt] == 0话,我们能说他没有被覆盖吗,不能,只能说没有被完全覆盖,为什么呢,因为他的子节点可能被完全覆盖了,但是父亲节点没有覆盖,那么怎么完全的不漏的得到这个区间被完全覆盖的区间大小呢,可以直接通过子节点覆盖的值

Sum[rt] = Sum[rt << 1] + Sum[rt << 1|1]得到rt这个位置总覆盖区间




题目https://nanti.jisuanke.com/t/17313

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
const int maxn=1e6+10;

#define mm(a) memset(a,0,sizeof(a))

int num1[maxn*4];
int num[maxn*4],X[maxn*4];
struct edge
{
    int l,r,h;
    int s;//s为1是下边,s为-1是上边
    edge() {};
    edge(int a,int b,int c,int d) : l(a),r(b),h(c),s(d) {}
    bool operator<(const edge &n)const
    {
        return h<n.h;
    }
} ss[maxn];

void pushup(int le,int ri,int node)
{
    if(num1[node])
        num[node]=X[ri+1]-X[le];
    else if(le==ri)
        num[node]=0;          
    else
        num[node]=num[node<<1]+num[node<<1|1];
}
void update(int l,int r,int add,int le,int ri,int node)
{
    if(l<=le&&ri<=r)
    {
        num1[node]+=add;//与懒惰标记类似
        pushup(le,ri,node);
        return ;
    }
    int t=(le+ri)>>1;
    if(l<=t) update(l,r,add,le,t,node<<1);
    if(r>t) update(l,r,add,t+1,ri,node<<1|1);
    pushup(le,ri,node);
}
int main()
{
    int n;
    while(scanf("%d",&n) != EOF)
    {
        if(n == 0)
        {
            cout << "*" << endl;
            break;
        }
        int a,b,c,d;
        int k=0;
        for(int i=0; i<n; i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            X[k]=a;
            ss[k++]=edge(a,c,b,1);
            X[k]=c;
            ss[k++]=edge(a,c,d,-1);
        }
        sort(X,X+k);
        sort(ss,ss+k);//按高度排
        int k1=1;
        for(int i=1; i<k; i++) //对X进行离散化 就是将每个点的横坐标排序之后有顺序地存储在X中,就不用浪费其他空间了(对于疏散点而言)
        {
            if(X[i]!=X[i-1]) X[k1++]=X[i];
        }
        mm(num);
        mm(num1);
        int ans=0;
        for(int i=0; i<k-1; i++)//扫描线,想象有一条线从纵坐标最小的点开始扫过,一直到纵坐标最大的点
        {

            int l=lower_bound(X,X+k1,ss[i].l)-X;
            int r=lower_bound(X,X+k1,ss[i].r)-X-1;
            update(l,r,ss[i].s,0,k1-1,1);
            ans+=num[1]*(ss[i+1].h-ss[i].h);//num[1]为当前横坐标的有效长度
        }
        cout << ans << endl;
    }
    return 0;
}

posted @ 2018-04-07 16:42  LandingGuys  阅读(171)  评论(0)    收藏  举报