HDU 1542 Atlantis(线段树——扫描线 :基础面积并模板,离散x坐标,从下向上扫描 )

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<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.

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 

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int MAXN = 105;

struct Line{
    double l,r,h;//描线的左端x坐标,扫描线的右端x坐标,扫描线的高度   
    int flag;//为-1或1,标记扫描线是矩形的上位还是下位边.
    Line(){}
    Line(double a,double b,double c,int d):l(a),r(b),h(c),flag(d){}
    bool operator < (const Line &b)const{
        return h < b.h;
    }
}L[MAXN*2];//记录扫描线的信息 

double X[MAXN*2];//记录端点x坐标   

struct T{
    double len,value;
    int flag;//表示当前区间覆盖了几次,如果flag = -1代表其儿子节点的flag值不一致。
    bool lazy;
}Tree[MAXN*8];

void Build(int temp,int left,int right){
    Tree[temp].len = X[right+1]-X[left];//这里一定要想明白为啥right+1。
    //因为Tree[temp].len是区间left一直到区间right的长度和。 
    Tree[temp].value = 0.0;
    Tree[temp].flag = 0;
    Tree[temp].lazy = false;
    if(left == right)return;
    int mid = left + (right-left)/2;
    Build(temp<<1,left,mid);
    Build(temp<<1|1,mid+1,right);
}

void Up(int temp){
    if(Tree[temp<<1].flag == -1 || Tree[temp<<1|1].flag == -1)Tree[temp].flag = -1;
    else if(Tree[temp<<1].flag != Tree[temp<<1|1].flag)Tree[temp].flag = -1;
    else Tree[temp].flag = Tree[temp<<1].flag;
    Tree[temp].value = Tree[temp<<1].value + Tree[temp<<1|1].value;
}

void PushDown(int temp){
    if(Tree[temp].lazy){
        Tree[temp<<1].flag = Tree[temp<<1|1].flag = Tree[temp].flag;
        Tree[temp<<1].lazy = Tree[temp<<1|1].lazy = true;
        Tree[temp].lazy = false;
        if(Tree[temp].flag > 0){
            Tree[temp<<1].value = Tree[temp<<1].len;
            Tree[temp<<1|1].value = Tree[temp<<1|1].len;
        }
        else Tree[temp<<1].value = Tree[temp<<1|1].value = 0.0;
    }
}

void Updata(int temp,int left,int right,int ql,int qr,int flag){
    if(ql>right || qr<left)return;
    if(ql<=left && qr>=right && Tree[temp].flag!=-1){
        Tree[temp].lazy = true;
        Tree[temp].flag += flag;
        if(Tree[temp].flag > 0)Tree[temp].value = Tree[temp].len;
        else Tree[temp].value = 0;
        return ;
    }
    PushDown(temp);
    int mid = left + (right-left)/2;
    if(ql<=mid)Updata(temp<<1,left,mid,ql,qr,flag);
    if(qr>mid)Updata(temp<<1|1,mid+1,right,ql,qr,flag);
    Up(temp);
}

int Bin(double key,int right){//二分查找端点x坐标key在X中的下标   
    int left = 0,mid;
    while(left<=right){//这里必须是<=(跟题没关系,二分查找的要求) 
        mid = left + (right-left)/2;
        if(X[mid] == key)return mid;
        else if(X[mid]>key)right = mid-1;
        else left = mid+1;
    }
    return -1;
}

double Solve(int t1,int m){
    double ans = 0.0;//最终面积 
    Build(1,1,t1-1);//注意线段树建树,用点建树和用段建树的区别
    /*要注意我们线段树中每个叶节点不是指X[L]坐标,而是指区间[X[L],X[L+1]]. 
    线段树中其他非叶节点控制的区间[L,R],也是指的x坐标轴的第L个区间到 
    R个区间的范围,也就是X[L]到X[R+1]坐标的范围.*/  
    for(int i=1 ; i<m ; i++){
        Updata(1,1,t1-1,Bin(L[i].l,t1),Bin(L[i].r,t1)-1/*这里一定要注意减一*/,L[i].flag);
        ans += Tree[1].value * (L[i+1].h-L[i].h);//注意这里必须是L[i+1]-L[i]
    }
    return ans;
}

int main(){
    
    int N;
    int casen = 0;
    double x1,x2,y1,y2;
    while(scanf("%d",&N) && N){
        int m = 0,n = 0;
         for(int i=0 ; i<N ; i++){
             scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
             L[++m] = Line(x1,x2,y1,1);
             L[++m] = Line(x1,x2,y2,-1);
             X[++n] = x1;
             X[++n] = x2;
         }
         sort(L+1,L+1+m);
         sort(X+1,X+1+n);
         int t1 = unique(X+1,X+1+n)-X-1;
         printf("Test case #%d
Total explored area: %.2f

",++casen,Solve(t1,m));
    }
    
    return 0;
}




原文地址:https://www.cnblogs.com/vocaloid01/p/9514102.html