扫描线 + 线段树 HDU1542(覆盖矩形面积) + HDU1828(覆盖矩形周长)

Atlantis 

Atlantis

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 22879    Accepted Submission(s): 9083


 

Problem 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 island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

 

 

Input

The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1
The input file is terminated by a line containing a single 0. Don’t process it.

 

 

Output

For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.

Output a blank line after each test case.

 

 

Sample Input

2 10 10 20 20 15 15 25 25.5 0

 

 

Sample Output

Test case #1 Total explored area: 180.00

 

 

Source

Mid-Central European Regional Contest 2000

 

 

Recommend

linle

将y坐标保存并排序。 按x坐标离散化后建立线段树。

每次遇到一个矩形的下底边就将这个区间+1,表示这个区间已经被几条线段覆盖了。  遇到上边就-1, 每次更新后累加当前x坐标总区间被覆盖的长度乘以相邻两边的高度。线段树维护一个点集, 但是对于边的问题就会变得很麻烦,  我们可以按照区间左端点建立线段树, 那么一个点表示的就不是点了, 而是起点在这个点的一个线段。  例如更新区间[l, r), 就相当于更新标号为[l, r-1]的线段。 线段树维护左右端点是闭区间,这样就会导致连续区间中间出现断裂,所以要维护左闭右开的区间

M 表示当前扫描的线的长度

Line 保存线的信息,l 左端点, r右端点, h为高度, f标记上边还是下边

#include 
#define FOR(I,S,T) for(int I=(S);I<=(T);I++)
using namespace std;
const int maxn = 200+5;
double M[maxn * 4];
struct Line{
    double l, r, h;
    int f;
}l[maxn];

int tag[maxn * 4];
vector  v;

int getid(double x){
    return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}

void gather(int p, int l, int r){
    if (tag[p]) M[p] = v[r] - v[l - 1];
    else if (l == r) M[p] = 0;
    else M[p] = M[p << 1] + M[p << 1 | 1];
}

void modify(int p, int tl, int tr, int l, int r, int val){
    if (tl > tr) return ;
    if (tl > r || tr< l) return;
    if (tl >= l && r >= tr){
        tag[p] += val;
        gather(p, tl, tr);
        return ;
    }
    int mid = (tl + tr) / 2;
    if (mid >= l) modify(p << 1, tl, mid, l ,r, val);
    if (mid < r) modify(p << 1 | 1, mid + 1, tr, l, r, val);
    gather(p, tl, tr);
}
int n;
bool cmp(Line a, Line b){return a.h < b.h;}

int main()
{
    int T = 0;
    while (~scanf("%d", &n) && n){
        double x1, x2, y1, y2;
        int cnt = 0;
        v.clear();
        for (int i = 0; i <= n; i++) l[i].l = l[i].r = l[i].h = l[i].f = 0;
        FOR(i, 1, n){
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            ++cnt, l[cnt].l = x1, l[cnt].r = x2, l[cnt].h = y1, l[cnt].f = 1;
            ++cnt, l[cnt].l = x1, l[cnt].r = x2, l[cnt].h = y2, l[cnt].f = -1;
            v.emplace_back(x1);
            v.emplace_back(x2);
        }
        sort(l + 1, l + 1 + cnt, cmp);
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(),v.end()), v.end());
        for(int i = 0; i <= 4 * n + 1; i++ ) tag[i] = M[i] = 0;
        double ans = 0.0;
        for (int i = 1; i < cnt; i++){
            int x = getid(l[i].l), y = getid(l[i].r);
            //cout << x << " " << y << endl;
            modify(1, 1, (int)v.size(), x, y - 1, l[i].f); //左闭右开
            ans += (l[i + 1].h - l[i].h) * M[1];
            //cout <

Picture 

Picture

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 7445    Accepted Submission(s): 3396


 

Problem Description

A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or horizontal. Each rectangle can be partially or totally covered by the others. The length of the boundary of the union of all rectangles is called the perimeter. 

Write a program to calculate the perimeter. An example with 7 rectangles is shown in Figure 1. 

 

扫描线 + 线段树 HDU1542(覆盖矩形面积) + HDU1828(覆盖矩形周长)_第1张图片



The corresponding boundary is the whole set of line segments drawn in Figure 2. 
 

扫描线 + 线段树 HDU1542(覆盖矩形面积) + HDU1828(覆盖矩形周长)_第2张图片



The vertices of all rectangles have integer coordinates.

 

 

Input

Your program is to read from standard input. The first line contains the number of rectangles pasted on the wall. In each of the subsequent lines, one can find the integer coordinates of the lower left vertex and the upper right vertex of each rectangle. The values of those coordinates are given as ordered pairs consisting of an x-coordinate followed by a y-coordinate. 

0 <= number of rectangles < 5000 
All coordinates are in the range [-10000,10000] and any existing rectangle has a positive area.

Please process to the end of file.

 

 

Output

Your program is to write to standard output. The output must contain a single line with a non-negative integer which corresponds to the perimeter for the input rectangles.

 

 

Sample Input

7 -15 0 5 10 -5 8 20 25 15 -4 24 14 0 -6 16 4 2 15 10 22 30 10 36 20 34 0 40 16

 

 

Sample Output

228

 

 

Source

IOI 1998

 

 

Recommend

linle 

方法一:从竖直方向和垂直方向分别左两次扫描线,用上面的代法稍微改改就行了

方法二:只做一次扫描线,比如说做竖直方向,那么水平方向的长度就可以算出来了。再计算竖直方向的时候,如果我们知道当前维护的区间有几段线段组成,用相邻两水平直线的高度*2*线段数量就可以算出竖直线段的长度

M 表示当前扫描的线的长度

Line 保存线的信息,l 左端点, r右端点, h为高度, f标记上边还是下边

num 当前有多少个线段

lh 这段区间的左端点有没有被覆盖(0没有,1有)

rh 这段区间的有端点有没有被覆盖(0没有,1有)

在线段树向上合并的时候 两个子区间合并成一个区间是,如果左区间的右端点被线段覆盖,并且右区间的左端点被线段覆盖,哪个合并以后的线段数量是左右区间的线段数量之和减一,否则是左右区间的线段数量之和

code改的上面的程序,但是这题不用double,懒得改了

#include 
#define FOR(I,S,T) for(int I=(S);I<=(T);I++)
using namespace std;
const int maxn = 10000+5;
double M[maxn * 4], num[maxn << 2], lh[maxn<<2], rh[maxn << 2];
struct Line{
    double l, r, h;
    int f;
}l[maxn];

int tag[maxn * 4];
vector  v;

int getid(double x){
    return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}

void gather(int p, int l, int r){
    if (tag[p]) {
        M[p] = v[r] - v[l - 1];
        lh[p] = rh[p] = num[p] = 1;
    }
    else if (l == r) {
        M[p] = 0;
        lh[p] = rh[p] = num[p] = 0;
    }
    else{
        M[p] = M[p << 1] + M[p << 1 | 1];
        num[p] = num[p << 1] + num[p << 1 | 1];
        lh[p] = lh[p << 1]; rh[p] = rh[p << 1 | 1];
        if (rh[p << 1] && lh[p << 1 | 1]) num[p]--;
    }
}

void modify(int p, int tl, int tr, int l, int r, int val){
    if (tl > tr) return ;
    if (tl > r || tr< l) return;
    if (tl >= l && r >= tr){
        tag[p] += val;
        gather(p, tl, tr);
        return ;
    }
    int mid = (tl + tr) / 2;
    if (mid >= l) modify(p << 1, tl, mid, l ,r, val);
    if (mid < r) modify(p << 1 | 1, mid + 1, tr, l, r, val);
    gather(p, tl, tr);
}
int n;
bool cmp(Line a, Line b){
    if (a.h == b.h){
        if (a.l == b.l) return a.r < b.r;
        return a.l < b.l;
    }
    return a.h < b.h;
}

int main()
{
    int T = 0;
    while (~scanf("%d", &n)){
        if (n == 0){
            puts("0");
            continue;
        }
        double x1, x2, y1, y2;
        int cnt = 0;
        v.clear();
        for (int i = 0; i <= n; i++) l[i].l = l[i].r = l[i].h = l[i].f = 0;
        FOR(i, 1, n){
            scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
            ++cnt, l[cnt].l = x1, l[cnt].r = x2, l[cnt].h = y1, l[cnt].f = 1;
            ++cnt, l[cnt].l = x1, l[cnt].r = x2, l[cnt].h = y2, l[cnt].f = -1;
            v.emplace_back(x1);
            v.emplace_back(x2);
        }
        sort(l + 1, l + 1 + cnt, cmp);
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(),v.end()), v.end());
        for(int i = 0; i <= 4 * n + 1; i++ ) tag[i] = M[i] = lh[i] = rh[i] = num[i] = 0;
        double ans = 0.0, laslen = 0.0;
        for (int i = 1; i <= cnt; i++){
            int x = getid(l[i].l), y = getid(l[i].r);
            //cout << x << " " << y << endl;
            modify(1, 1, (int)v.size(), x, y - 1, l[i].f); //左闭右开
            ans += fabs(M[1] - laslen) + 2.0 * num[1] * (l[i + 1].h - l[i].h);
            laslen = M[1];
            //cout <

 

你可能感兴趣的:(模板,acm)