题目原链接:http://poj.org/problem?id=1151
题目中文翻译:
POJ 1151 Atlantis
Time Limit: 1000MS |
Memory Limit: 10000K |
|
Total Submissions: 25769 |
Accepted: 9477 |
Description
有几个古希腊文本包含传说中的亚特兰蒂斯岛的描述。 其中一些文本甚至包括岛屿部分地图。 但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。 您的朋友Bill必须知道地图的总面积。 你(不明智地)自告奋勇写了一个计算这个数量的程序。
Input
输入包含几个测试用例。 每个测试用例都以一行包含一个整数n(1 <= n <= 100)开始,指示可用的地图。以下n行描述了每个地图。 这些行中的每一行包含四个数字x1; y1; x2; y2(0 <= x1 <x2 <= 100000; 0 <= y1 <y2 <= 100000),不一定是整数。 值(x1; y1)和(x2; y2)是地图左上角和右下角的坐标。
输入文件以包含单个0的行作为终止。不处理它。
Output
对于每个测试用例,您的程序应输出一个部分。 每个部分的第一行必须是“Test case #k”,其中k是测试用例的编号(从1开始)。 第二个必须是“Total explored area:a”,其中a是总探索区域(即此测试用例中所有矩形的覆盖区域),精确到小数点后两位数。
在每个测试用例后输出一个空行。
Sample Input
2
10 10 20 20
15 15 25 25.5
0
Sample Output
Test case #1
Total explored area: 180.00
解题思路:
本人太菜,无法描述,请看大佬详解:AKIOI
AC代码:
(由此大佬博客借鉴而来:code)
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 5 using namespace std; 6 7 struct kkk{//线段树 8 int l,r;//线段树的左右整点 9 int c;//c用来记录重叠情况 10 double cnt,lf,rf;//cnt用来计算实在的长度,lf,rf分别是对应的左右真实的浮点数端点 11 }s[603]; 12 13 struct k2{ 14 double x,y1,y2; 15 int f; 16 }l[603]; 17 //把一段段平行于y轴的线段表示成数组 , 18 //x是线段的x坐标,y1,y2线段对应的下端点和上端点的坐标 19 //一个矩形 ,左边的那条边f为1,右边的为-1, 20 //用来记录重叠情况,可以根据这个来计算,kkk节点中的c 21 22 double y[201];//记录y坐标的数组 23 24 bool cmp(k2 a,k2 b) { 25 return a.x < b.x; 26 } 27 28 void build(int t,int l,int r) { 29 s[t].l = l;s[t].r = r; 30 s[t].cnt = s[t].c = 0; 31 s[t].lf = y[l]; 32 s[t].rf = y[r]; 33 if(l + 1 == r) return ; 34 int mid = (l + r) >> 1; 35 build(t << 1,l,mid); 36 build(t << 1 | 1,mid,r); 37 } 38 39 void calen(int t) {//计算长度 40 if(s[t].c > 0) {// t对应对节点有线段覆盖 41 s[t].cnt = s[t].rf - s[t].lf; 42 return ; 43 } 44 // 现在是t对应的线段没有完整的被覆盖,但是他的孩子节点可能部分被覆盖 45 if(s[t].l + 1 == s[t].r) s[t].cnt = 0;//线段树叶子结点,代表一个点,特判,长度为0 46 else s[t].cnt = s[t<<1].cnt + s[t<<1|1].cnt;//否则,用孩子的和来表示 47 } 48 49 50 void update(int t,k2 e) {//加入线段e,后更新线段树 51 if(e.y1 == s[t].lf && e.y2 == s[t].rf) {//如果正好找到区间 52 s[t].c += e.f; 53 calen(t); 54 return ; 55 } 56 if(e.y2 <= s[t<<1].rf) update(t<<1,e);//下传左儿子 57 else if(e.y1 >= s[t<<1|1].lf) update(t<<1|1,e);//下传右儿子 58 else {//左右儿子都下传 59 k2 tmp = e; 60 tmp.y2 = s[t<<1].rf; 61 update(t<<1,tmp); 62 tmp = e; 63 tmp.y1 = s[t<<1|1].lf; 64 update(t<<1|1,tmp); 65 } 66 calen(t); 67 } 68 69 int main() { 70 int i,n,t,aa = 0; 71 double x1,y1,x2,y2; 72 while(scanf("%d",&n),n) { 73 aa++; 74 t = 1; 75 for(int i = 1;i <= n; i++) { 76 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 77 l[t].x = x1; 78 l[t].y1 = y1; 79 l[t].y2 = y2; 80 l[t].f = 1; 81 y[t++] = y1; 82 l[t].x = x2; 83 l[t].y1 = y1; 84 l[t].y2 = y2; 85 l[t].f = -1; 86 y[t++] = y2; 87 } 88 sort(l+1,l+t,cmp); 89 sort(y+1,y+t); 90 build(1,1,t-1);//建树 91 update(1,l[1]);//下传lazy标记 92 double res = 0; 93 for(int i = 2;i < t; i++) { 94 res += s[1].cnt * (l[i].x - l[i-1].x); 95 update(1,l[i]); 96 } 97 printf("Test case #%d Total explored area: %.2f ",aa,res); 98 } 99 }