大二训练第二周 D - 覆盖的面积 离散化坐标加线段树

D - 覆盖的面积
Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u
Submit  Status

Description

给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 


 

Input

输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000. 

注意:本题的输入数据较多,推荐使用scanf读入数据. 
 

Output

对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数. 
 

Sample Input

      
      
      
      
2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1
 

Sample Output

      
      
      
      
7.63 0.00
#pragma warning(disable:4786)//使命名长度不受限制
#pragma comment(linker, "/STACK:102400000,102400000")//手工开栈
#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <stack>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define rds(x) scanf("%s",x)
#define rdc(x) scanf("%c",&x)
#define ll long long int
#define maxn 100005
#define mod 1000000007
#define INF 0x3f3f3f3f //int 最大值
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define MT(x,i) memset(x,i,sizeof(x))
#define PI  acos(-1.0)
#define E  exp(1)
using namespace std;
struct nline{
    double x1,x2,h;
    int flag;
    void init(double a,double b,double c,int f){
        x1=a;x2=b;h=c;flag=f;
    }
}line[maxn];
bool cmp(nline a,nline b){return a.h<b.h;}
struct node{
    int cnt,left,right;
    double len,nlen;
}tree[maxn<<2];
int loop,n,pos,pp;
double x[maxn],ans;
void creatTree(int st,int left,int right){
    tree[st].cnt=tree[st].len=tree[st].nlen=0;
    tree[st].left=left;tree[st].right=right;
    if(left==right)return ;
    int m=(tree[st].left+tree[st].right)>>1;
    int temp=st<<1;
    creatTree(temp,left,m);
    creatTree(temp|1,m+1,right);
}
int mysearch(double data,int st,int ed){
    while(st<=ed){
        int mid=(st+ed)>>1;
        if(x[mid]==data)
            return mid;
        else if(x[mid]<data)st=mid+1;
        else ed=mid-1;
    }
}
void push_up(int st){
    int m=st<<1;
    if(tree[st].cnt)tree[st].len=x[tree[st].right+1]-x[tree[st].left];
    else if(tree[st].left==tree[st].right)tree[st].len=0;
    else tree[st].len=tree[m].len+tree[m+1].len;

    if(tree[st].cnt>1)tree[st].nlen=x[tree[st].right+1]-x[tree[st].left];
    else if(tree[st].left==tree[st].right)tree[st].nlen=0;
    else if(tree[st].cnt==1)tree[st].nlen=tree[m].len+tree[m+1].len;
    else tree[st].nlen=tree[m].nlen+tree[m+1].nlen;
}
void updata(int st,int f,int left,int right){
    if(tree[st].left==left&&tree[st].right==right){
        tree[st].cnt+=f;
        push_up(st);
        return;
    }
    int m=(tree[st].left+tree[st].right)>>1;
    int temp=st<<1;
    if(right<=m) updata(temp,f,left,right);
    else if(left>m) updata(temp+1,f,left,right);
    else {
        updata(temp,f,left,m);
        updata(temp+1,f,m+1,right);
    }
    push_up(st);
}
int main(){
    rd(loop);
    while(loop--){
        rd(n);pos=pp=0;
        double x1,x2,y1,y2;
        FOR(i,1,n){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[pos++].init(x1,x2,y1,1);
            line[pos++].init(x1,x2,y2,-1);
            x[pp++]=x1;x[pp++]=x2;
        }
        sort(x,x+pp);
        sort(line,line+pos,cmp);
        int m=1;
        for(int i=1;i<pp;i++)
            if(x[i]!=x[i-1])
                x[m++]=x[i];
        creatTree(1,0,m-1);
        ans=0;
        for(int i=0;i<pp-1;i++){
            int a=mysearch(line[i].x1,0,m-1);
            int b=mysearch(line[i].x2,0,m-1)-1;
            updata(1,line[i].flag,a,b);
            ans+=tree[1].nlen*(line[i+1].h-line[i].h);
        }
        printf("%.2lf\n",ans+.004);
    }
    return 0;
}
/*
2
5
1 1 4 2
1 3 3 7
2 1.5 5 4.5
3.5 1.25 7.5 4
6 3 10 7
3
0 0 1 1
1 0 2 1
2 0 3 1
*/



你可能感兴趣的:(C++,线段树)