Atlantis(线段树+扫描线)
Atlantis
InputThe 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.OutputFor 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
题意:给出矩形的左下和右上两个端点的横纵坐标,求出所有矩形的面积,覆盖部分算一次。
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int maxn=1100;
7 struct node{
8 double l,r,val;
9 int f,d;
10 }tree[maxn<<2];
11 struct node2{
12 double l,r,h;
13 int f;
14 }e[maxn<<2];
15 double a[maxn<<2];
16 int n;
17 bool cmp(node2 a,node2 b)
18 {
19 return a.h<b.h;
20 }
21 void pushup(int cur)
22 {
23 if(tree[cur].f>0)//就比如说我要更新10-20,现在处于10-15的区间即cur=2
24 {
25 tree[cur].val=(tree[cur].r-tree[cur].l);
26 }
27 else if(tree[cur].d==1)
28 {
29 tree[cur].val=0;
30 }
31 else
32 {
33 tree[cur].val=tree[cur*2].val+tree[cur*2+1].val;//例如当cur=1,tree[cur].val就等于其左子树10-15的val值加上右子树保存的15-20的val值
34 }
35 }
36 void build(int l,int r,int cur)//第一次调用l=1 r=4相当于用区间1-4表示横坐标10-25的区间
37 {
38 tree[cur].l=a[l];
39 tree[cur].r=a[r];
40 tree[cur].f=0;
41 tree[cur].val=0;
42 if(l+1==r)//离散化后的区间最小值,比如2-3就是一个线段的最小值,3-3就只能表示一个点
43 {
44 tree[cur].d=1;//相当于已经到了叶子节点
45 return ;//详见下图(1)
46 }
47 tree[cur].d=0;
48 int mid=(l+r)/2;
49 build(l,mid,cur*2);//因为是区间1-3 应该分为1-2和2-3
50 build(mid,r,cur*2+1);//所以mid不用加一
51 }
52 void update(double pl,double pr,int f,int cur)
53 {
54 if(pl<=tree[cur].l&&tree[cur].r<=pr)
55 {
56 tree[cur].f+=f;
57 pushup(cur);
58 return ;
59 }
60 if(pl<tree[cur*2].r) update(pl,pr,f,cur*2);
61 if(pr>tree[cur*2+1].l) update(pl,pr,f,cur*2+1);
62 pushup(cur);
63 }
64 int main()
65 {
66 int T=1;
67 while(~scanf("%d",&n)&&n)
68 {
69 double x1,x2,y1,y2;
70 for(int i=1;i<=n;i++)
71 {
72 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
73 e[i*2-1].l=x1;e[i*2-1].r=x2;//记录每一条线段的左右端点
74 e[i*2-1].h=y1;e[i*2-1].f=1;//f=1表示进入该矩形
75 e[i*2].l=x1;e[i*2].r=x2;
76 e[i*2].h=y2;e[i*2].f=-1;//f=-1表示出该矩形
77 a[2*i-1]=x1;
78 a[2*i]=x2;
79 }
80 sort(a+1,a+1+n*2);//将横坐标从小到大排序,为将其离散化做准备
81 int k=1;
82 for(int i=2;i<=n*2;i++)
83 {
84 if(a[i]!=a[i-1])
85 a[++k]=a[i];
86 }//去重并离散化 例如题目样例对应a[1]=10 a[2]=15 a[3]=20 a[4]=25
87 build(1,k,1);
88 sort(e+1,e+1+2*n,cmp);//将矩形按高度从小到大排序,因为扫描线是从下往上扫
89 double ans=0;
90 for(int i=1;i<=n*2;i++)
91 {
92 ans+=(e[i].h-e[i-1].h)*tree[1].val;
93 update(e[i].l,e[i].r,e[i].f,1);
94 }
95 printf("Test case #%d\nTotal explored area: %.2lf\n\n",T++,ans);
96 }
97 }