poj1151 Atlantis(線段樹+離散化+掃描線)
阿新 • • 發佈:2018-11-10
題意:給出一堆座標,問最後構成的面積有多少(重複的面積只能算一次)
思路:首先,這道題的資料量完全可以暴力過的,但是下面這麼做只是想練練線段樹和離散化的結合。給出的座標不是整數,所以可以這麼做。把各個x,從小到大掃描,然後對所有y值進行離散化,給其一個整數標號,這樣y就可以用線段樹進行維護了。然後沒掃描一條x縱線就決定是從線段樹中去除還是增加那一條線段,然後算面積。
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<vector> using namespace std; struct node1 { double x,y1,y2; int fg; node1(double x,double y1,double y2,int fg):x(x),y1(y1),y2(y2),fg(fg){} }; struct node2 { double l,r,sum; int num; }s[100000]; vector<node1> s1; int n; double y[1000]; bool cmp(node1 a,node1 b) { return a.x<b.x; } void make_tree(int root,int l,int r) { //cout<<root<<" "<<l<<" "<<r<<endl; s[root].l=y[l]; s[root].r=y[r]; s[root].sum=0; s[root].num=0; if(r-l<=1) return; int mid=(l+r)/2; make_tree(root*2,l,mid); make_tree(root*2+1,mid,r); } void push_up(int root) { if( s[root].num>0 ) s[root].sum = s[root].r - s[root].l ; else s[root].sum = s[2*root].sum + s[2*root+1].sum ; } void update(int root,int fg,double l,double r) { if(s[root].l==l&&s[root].r==r) { s[root].num+=fg; push_up(root); return; } if(s[root*2].r>l) { update(root*2,fg,l,min(r,s[root*2].r)); } if(s[root*2+1].l<r) { update(2*root+1,fg,max(s[root*2+1].l,l),r); } push_up(root); } int main() { //freopen("t.txt","r",stdin); double x1,y1,x2,y2; int cnt=1; while(scanf("%d",&n)!=EOF) { if(n==0) break; memset(s,0,sizeof(s)); s1.clear(); for(int i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); s1.push_back(node1(x1,y1,y2,1)); s1.push_back(node1(x2,y1,y2,-1)); y[2*i+1]=y1; y[2*i+2]=y2; } sort(s1.begin(),s1.end(),cmp); sort(y+1,y+1+2*n); make_tree(1,1,2*n); update(1,s1[0].fg,s1[0].y1,s1[0].y2); double sum=0; for(int i=1;i<2*n;i++) { sum+=(s1[i].x-s1[i-1].x)*s[1].sum; update(1,s1[i].fg,s1[i].y1,s1[i].y2); } printf("Test case #%d\nTotal explored area: %.2lf\n\n",cnt++,sum); } return 0; }