hdu 1542 Atlantis (線段樹+掃描線)
阿新 • • 發佈:2018-08-25
over down first uniq sed spa 問題 rec style
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
Atlantis
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 18559 Accepted Submission(s): 7523
The input file is terminated by a line containing a single 0. Don’t process it.
Output a blank line after each test case.
Sample Output Test case #1 Total explored area: 180.00
題目來源: http://acm.hdu.edu.cn/showproblem.php?pid=1542 題目大意: 再一個平面上給你一些矩形,要你求矩形一共覆蓋的面積。 線段樹掃描線求面積。 這個問題,還是推薦一篇博客,我就只談談對博客的感想: 【hdu1542】線段樹求矩形面積並 - 攔路雨偏似雪花 - 博客園 首先,給的數據是浮點數,一定要離散化,最好要去重。我這裏手寫一份自己常用的適應性很高離散化代碼(去重),大家可以自己拿去調試一下。到本題中還是要有不小的改動,代碼後面也會貼出來,讀者可以對比一下。
#include<cstdio> #include<algorithm> using namespace std; const int N=100007; int t[N],a[N]; int main() { int n; scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%d",a+i); t[i]=a[i]; } sort(t,t+n); int m=unique(t,t+n)-t;//共有每個不重復的元素 for(int i=0;i<n;i++) a[i]=lower_bound(t,t+m,a[i])-t+1;//從1開始編號 for(int i=0;i<n;i++) printf("%d ",a[i]);//測試輸出 return 0; }View Code
之前建線段樹都是以某個點為葉子結點的,但是這次卻不能這麽寫,而要以單位長度為葉子結點。
線段樹主要維護cnt(-1表示覆蓋不明確,>=0表示完全覆蓋cnt次,模仿海報問題),len(區間長度,這就要求離散化的時候建立離散後的數值與原數值的映射)。
其他的參考那篇博客就好啦。
#include<cstdio> #include<algorithm> using namespace std; double t[410];//排序數組 double a[410];//原始數據 int b[410];//離散後的數據 double c[410];//離散後的數據到原數據的映射 struct tsegment { int x1,x2; int y; int flag; }; tsegment segment[210]; int cmp(tsegment a,tsegment b) { return a.y<b.y; } struct ttree { int l,r; int cover;//-1不確定 >=0完全覆蓋次數 就不打tag了,時間可能會長點 double len;//區間長度 }; ttree tree[400*4+20]; void pushup(int x) { if(tree[x].l+1==tree[x].r) return; if(tree[x*2].cover==tree[x*2+1].cover&&tree[x*2].cover>=0) tree[x].cover=tree[x*2].cover; else tree[x].cover=-1; } void pushdown(int x) { if(tree[x].l+1==tree[x].r) return; if(tree[x].cover>=0) tree[x*2].cover=tree[x*2+1].cover=tree[x].cover; } void build(int x,int l,int r) { tree[x].l=l; tree[x].r=r; tree[x].len=c[r]-c[l]; tree[x].cover=0; if(l+1<r) { int mid=(l+r+1)/2; build(x*2,l,mid); build(x*2+1,mid,r);//葉子節點為一小段區間 } } void modify(int x,int l,int r,int flag) { if(l<=tree[x].l&&r>=tree[x].r&&tree[x].cover>=0) { tree[x].cover+=flag; //printf("%d %d\n",tree[x].l,tree[x].r); } else if(tree[x].l+1<tree[x].r) { pushdown(x); int mid=(tree[x].l+tree[x].r+1)/2; if(l<mid) modify(x*2,l,r,flag); if(r>mid) modify(x*2+1,l,r,flag); pushup(x); } } double query(int x) { if(tree[x].cover>0) return tree[x].len; else if(tree[x].cover==0) return 0; else { pushdown(x); double ret=0; ret+=query(x*2); ret+=query(x*2+1); return ret; } } int main() { int n,k=1; while(scanf("%d",&n),n) { for(int i=0;i<n*4;i++) { scanf("%lf",a+i); t[i]=a[i]; } sort(t,t+n*4); int m=unique(t,t+n*4)-t;//共有m個不同的數據 for(int i=0;i<n*4;i++) { b[i]=lower_bound(t,t+m,a[i])-t+1;//編號從1開始 c[b[i]]=a[i]; } //for(int i=1;i<=m;i++) printf("%f\n",c[i]); for(int i=0;i<n;i++) { int x1=b[i*4],y1=b[i*4+1]; int x2=b[i*4+2],y2=b[i*4+3]; segment[i*2].x1=x1;segment[i*2].x2=x2; segment[i*2].y=y1;segment[i*2].flag=1; segment[i*2+1].x1=x1;segment[i*2+1].x2=x2; segment[i*2+1].y=y2;segment[i*2+1].flag=-1; } sort(segment,segment+n*2,cmp); build(1,1,m); modify(1,segment[0].x1,segment[0].x2,segment[0].flag); double ans=0; for(int i=1;i<n*2;i++) { //printf("%.2f\n",query(1)); //printf("%d %d\n",segment[i].x1,segment[i].x2); ans=ans+query(1)*(c[segment[i].y]-c[segment[i-1].y]); modify(1,segment[i].x1,segment[i].x2,segment[i].flag); } printf("Test case #%d\nTotal explored area: %.2f\n\n",k++,ans); } return 0; }View Code
hdu 1542 Atlantis (線段樹+掃描線)