线段树 : 求矩形面积的并 ---- hnu : 12884 Area Coverage

Area Coverage
Time Limit: 10000ms, Special Time Limit:2500ms, Memory Limit:65536KB
Total submit users: 16, Accepted users: 12
Problem 12884 : No special judgement
Problem description

In this day and age, a lot of the spying on other countries is done with the use of satellites and drones equipped with cameras. All these photographs of various sizes and from various sources can be combined to give a picture of the country as a whole.
Given the photographs (that is to say, the rectangular
area covered by each, since the contents of the photographs themselves are of
course top-secret!), can you work out what the total area is of all that is
photographed? Note that certain areas can appear on multiple photographs and
should be counted only once.

Input

On the first line one positive number: the number of test cases, at most 100.
After that per test case:
one line with an integer n (1<=n<=1000):
the number of photographs.
n lines with four space-separated integers x1,
y1, x2 and y2 (0<=x1; y1; x2; y2<=1 000 000, x1 < x2 and y1 < y2):
the coordinates of the southwest and northeast corner, respectively, of each
photograph. The photographs are all rectangular in shape with their other
corners at (x1; y2) and (x2; y1).
The coordinates correspond to a flat
two-dimensional space (i.e. we assume the Earth to be
flat).

Output

Per test case:
one line with an integer: the total area of all that
appears on the photographs.

Sample Input
2
3
0 6 20 16
14 0 24 10
50 50 60 60
2
0 0 20 10
10 4 14 8
Sample Output
376
200
Problem Source
BAPC preliminary 2013


Mean:

在二维平面中,给你一些矩形的左下坐标(x1,y1)和右上坐标(x2,y2),让你求这些矩形面积的并。

analyse:

我们在y轴方向上维护一棵线段树。该线段树的模型是区间覆盖,即应该对像某个区间有没有被覆盖这样的查询,以及添加覆盖和删除覆盖这样的操作---也就是将矩形的左右两边界看作对y轴的覆盖来处理。我们将所有矩形的左右边界按照x坐标升序排序。每个矩形的左边界执行对y轴的覆盖操作,右边界执行对x轴的删除覆盖操作。

每次插入一条线段的时候,我们判断cover值(覆盖的次数),如果>0那么就算面积。

如图:

初始时每条线段的cover都为0;

线段1插入后,所对应的区间cover变为1,当第二条线段插入时,我们先判断一下该区间上的cover值,发现有一段cover是大于0的,所以就将对应的面积(蓝色部分)加入ans中,此时线段2下半部分的cover值变为2,上部分的cover值变为1,还要把线段1的上部分的x坐标更新为线段2的x值;

当第三条直线插入时,同样的道理,加入的是黄色部分的面积;第四条进入时,加入的是紫色部分的面积。

这样,我们只需要在插入前先计算面积,当所有线段插入结束,answer也就出来了。

所以我们的线段树只需要两个函数:build和insert函数。

Time complexity:O(n*logn)

Source code:

//Memory   Time
// 1347K   0MS
// by : Snarl_jsb
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<iomanip>
#include<string>
#include<climits>
#include<cmath>
#define MAX 1100
#define LL long long
using namespace std;
double y[2*MAX];
struct LINE
{
    double x,y_down,y_up;
    int flag;  //  左线段or右线段
};
LINE line[MAX<<1];
struct Tree
{
    int x;
    int cover;      //  覆盖次数
    bool flag;     //   是否为叶子节点
    int y_up,y_down;
};
Tree tree[(1010<<2)*4];

bool cmp(LINE a,LINE b)
{
    return a.x<b.x;
}

void build(int l,int r,int x)
{
    tree[x].x=-1;   //  -1表示该区间没有线段
    tree[x].cover=0;
    tree[x].flag=false;
    tree[x].y_up=y[r];
    tree[x].y_down=y[l];
    if(l+1==r)  // 叶子结点: (1,2) (2,3) (3,4) (4,5)....
    {
        tree[x].flag=true;
        return;
    }
    int tmp=x<<1;
    int mid=(l+r)>>1;
    build(l,mid,tmp);
    build(mid,r,tmp+1);;
}
double insert(int i,double x,double l,double r,int flag)
{
    if(r<=tree[i].y_down||l>=tree[i].y_up)  //要插入的线段不在该区间
        return 0;
    if(tree[i].flag)    //  叶子节点
    {
        if(tree[i].cover>0)      //    需要求并面积
        {
            double temp_x=tree[i].x;
            double ans=(x-temp_x)*(tree[i].y_up-tree[i].y_down);  //    宽*高
            tree[i].x=x;    //  更新树中的x值
            tree[i].cover+=flag;
            return ans;
        }
        else
            {
                tree[i].cover+=flag;
                tree[i].x=x;
                return 0;
            }
    }
    double ans1,ans2;
    int tmp=i<<1;
    ans1=insert(tmp,x,l,r,flag);
    ans2=insert(tmp+1,x,l,r,flag);
    return ans1+ans2;
}

int main()
{
//    freopen("cin.txt","r",stdin);
//    freopen("cout.txt","w",stdout);
    int T;
    cin>>T;
    double x1,y1,x2,y2;
    while(T--)
    {
        int n;
        cin>>n;
        int index=1;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
            y[index]=y1;
            line[index].x=x1;
            line[index].y_down=y1;
            line[index].y_up=y2;
            line[index].flag=1;
            index++;

            y[index]=y2;
            line[index].x=x2;
            line[index].y_down=y1;
            line[index].y_up=y2;
            line[index].flag=-1;
            index++;
        }
        index--;
        double ans=0.0;
        sort(line+1,line+1+index,cmp);
        sort(y+1,y+1+index);
        build(1,index,1);
        for(int i=1;i<=index;i++)
        {
            ans+=insert(1,line[i].x,line[i].y_down,line[i].y_up,line[i].flag);
        }
        printf("%.0lf\n",ans);
    }
    return 0;
}

  

线段树 : 求矩形面积的并 ---- hnu : 12884 Area Coverage

时间: 2024-07-29 10:27:01

线段树 : 求矩形面积的并 ---- hnu : 12884 Area Coverage的相关文章

POJ&#183;1151 Atlantis&#183;线段树求矩形面积并

题目在这:http://poj.org/problem?id=1151 Atlantis Time Limit: 1000MS   Memory Limit: 10000K Description There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the is

POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并

题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线段树维护两个值:cover和len,cover表示该线段区间目前被覆盖的线段数目,len表示当前已覆盖的线段长度(化为离散前的真值),每次加入一条线段,将其y_low,y_high之间的区间染上line[i].cover,再以tree[1].len乘以接下来的线段的x坐标减去当前x坐标,即计算了一部

UVA 11983 Weird Advertisement --线段树求矩形问题

题意:给出n个矩形,求矩形中被覆盖K次以上的面积的和. 解法:整体与求矩形面积并差不多,不过在更新pushup改变len的时候,要有一层循环,来更新tree[rt].len[i],其中tree[rt].len[i]表示覆盖次数大于等于i的线段长度,以便求面积,最后只要每次都用tree[1].len[K]来算面积即可. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cst

UVA 11983 Weird Advertisement(线段树求矩形并的面积)

UVA 11983 题目大意是说给你N个矩形,让你求被覆盖k次以上的点的总个数(x,y<1e9) 首先这个题有一个转化,吧每个矩形的x2,y2+1这样就转化为了求N个矩形被覆盖k次以上的区域的面积 由于坐标很大,首先考虑的就是将坐标离散化,然后建立线段树tree[][K],表示x的某个区间被覆盖了K次(大于K次算K次)的实际长度,在计算时把矩形转化为一系列横线段(就是说将一个矩形拆开为两条线段,下面的标记为1,上面的标记为-1(这里的标记很有技巧)),然后将这些线段按照y值的从小到达排序(y值相

UVA - 11983 Weird Advertisement (线段树求并面积)

Description G Weird Advertisement Renat Mullakhanov (rem), one of the most talented programmers in the world, passed away on March 11, 2011. This is very sad news for all of us. His team went to ACM ICPC World Finals - 2004, placed 4th and won gold m

poj 3277 City Horizon (线段树 扫描线 矩形面积并)

题目链接 题意: 给一些矩形,给出长和高,其中长是用区间的形式给出的,有些区间有重叠,最后求所有矩形的面积. 分析: 给的区间的范围很大,所以需要离散化,还需要把y坐标去重,不过我试了一下不去重 也不会出错, 所有的区间都能列出来,只是在查找的时候费点事. 给的矩形相当于在同一水平线上的,也就是y1坐标相当于为0,其他的就和 poj 1151 Atlantis 差不多了. 我写的思路是按照矩形面积并的思路写的: 但是还有另一种方法也是挺简单的,就是把给的矩形按照高从小到大排序,然后依次插入线段树

HDU 1264 Counting Squares (线段树-扫描线-矩形面积并)

Problem A : Counting Squares From:HDU, 1264 Problem Description Your input is a series of rectangles, one per line. Each rectangle is specified as two points(X,Y) that specify the opposite corners of a rectangle. All coordinates will be integers in t

HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板

好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 21978    Accepted Submission(s): 8714 Problem Description There are several anc

HDU 1828 / POJ 1177 Picture --线段树求矩形周长并

题意:给n个矩形,求矩形周长并 解法:跟求矩形面积并差不多,不过线段树节点记录的为: len: 此区间线段长度 cover: 此区间是否被整个覆盖 lmark,rmark: 此区间左右端点是否被覆盖 num: 此区间分离开的线段的条数 重点在转移的地方,不难理解. 代码: #include <iostream> #include <cmath> #include <iostream> #include <cstdio> #include <cstrin