hdu1255、1542(线段树求面积的交并)
http://acm.hdu.edu.cn/showproblem.php?pid=1255
http://acm.hdu.edu.cn/showproblem.php?pid=1542
思路:
嗯哼,要开始利用线段树求解矩形面积的并、交、以及周长了。先看一下吧
给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1)、(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1;另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1。根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序。
上图中,红色的字体表示的是该线段的cover值。刚刚开始的时候,线段树上的cover值都为0,但第一根线段(x==0)插入线段树的之后,我们将线段树上的cover加上该线段的cover,那么,此时线段树上被该线段覆盖的位置上的cover的值就为1,下次再插入第二根线段(x==1)此时发现该线段所覆盖的区间内,有一部分线段树的cover为0,另有一部分为1,仔细观察,但插入第二个线段的时候,如果线段树上cover已经为1的那些区间,和现在要插入的第二根线段之间,是不是构成了并面积?还不明白?看下图,绿色部分即为插入第二根线段后得到的并面积
够清楚了吧!也就是说,我们插入某跟线段的时候,只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的x定位 - 上一线段的x定位)*(该区间的大小)
1255:
#include<iostream> #include<algorithm> using namespace std; struct node { double x,up,down; int flag; }link[2005]; struct { double x,up,down; int cover,child; }tree[1000000]; double yy[2005]; int cmp(const double &a,const double &b) { if(a<b) return 1; else return 0; } int cmp1(const node &a,const node &b) { if(a.x<b.x) return 1; else return 0; } void build(int i,int l,int r) { tree[i].up=yy[r]; tree[i].down=yy[l]; tree[i].x=-1; tree[i].cover=0; tree[i].child=1; if(l+1==r) { tree[i].child=0; return ; } int mid=(l+r)/2; build(i*2,l,mid); build(i*2+1,mid,r); } double updata(int i,double l,double r,double x,int flag) { if(r<=tree[i].down||l>=tree[i].up) return 0; if(!tree[i].child) { if(tree[i].cover>1) { double ans=0; ans=(x-tree[i].x)*(tree[i].up-tree[i].down); tree[i].cover+=flag; tree[i].x=x; return ans; } else { tree[i].cover+=flag; tree[i].x=x; return 0; } } return updata(i*2,l,r,x,flag)+updata(i*2+1,l,r,x,flag); } int main() { int t; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); int i,j=1; for(i=1;i<=n;i++) { double x1,y1,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); link[j].x=x1; link[j].up=y2; link[j].down=y1; link[j].flag=1; yy[j]=y1; j++; link[j].x=x2; link[j].up=y2; link[j].down=y1; link[j].flag=-1; yy[j]=y2; j++; } sort(yy+1,yy+j,cmp); sort(link+1,link+j,cmp1); build(1,1,j-1); double ans=0; for(i=1;i<j;i++) { ans+=updata(1,link[i].down,link[i].up,link[i].x,link[i].flag); } printf("%.2lf\n",ans); } return 0; }
1542:
View Code
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 struct node 5 { 6 double x,up,down; 7 int flag; 8 }link[10000]; 9 struct node1 10 { 11 double x,up,down; 12 int cover,child; 13 }tree[100000]; 14 double yy[10000]; 15 int cmp(const double &a,const double &b) 16 { 17 if(a<b) 18 return 1; 19 else 20 return 0; 21 } 22 int cmp1(const node &a,const node &b) 23 { 24 if(a.x<b.x) 25 return 1; 26 else 27 return 0; 28 } 29 void build(int l,int r,int i) 30 { 31 int mid=(l+r)/2; 32 tree[i].up=yy[r]; 33 tree[i].down=yy[l]; 34 tree[i].x=-1; 35 tree[i].cover=0; 36 tree[i].child=1; 37 if(l+1==r) 38 { 39 tree[i].child=0; 40 return ; 41 } 42 build(l,mid,i*2); 43 build(mid,r,i*2+1); 44 } 45 double updata(int i,double down,double up,int flag,double x) 46 { 47 if(up<=tree[i].down||down>=tree[i].up) 48 return 0; 49 if(!tree[i].child) 50 { 51 if(tree[i].cover>0) 52 { 53 double ans=0; 54 ans+=(x-tree[i].x)*(tree[i].up-tree[i].down); 55 tree[i].x=x; 56 tree[i].cover+=flag; 57 return ans; 58 } 59 else 60 { 61 tree[i].x=x; 62 tree[i].cover+=flag; 63 return 0; 64 } 65 } 66 return updata(i*2,down,up,flag,x)+updata(i*2+1,down,up,flag,x); 67 } 68 int main() 69 { 70 int n,f=0,i; 71 while(scanf("%d",&n)>0&&n) 72 { 73 int j=1; 74 for(i=1;i<=n;i++) 75 { 76 double x1,y1,x2,y2; 77 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 78 link[j].x=x1; 79 link[j].down=y1; 80 link[j].up=y2; 81 link[j].flag=1; 82 yy[j]=y1; 83 j++; 84 link[j].x=x2; 85 link[j].down=y1; 86 link[j].up=y2; 87 link[j].flag=-1; 88 yy[j]=y2; 89 j++; 90 } 91 sort(yy+1,yy+j,cmp); 92 sort(link+1,link+j,cmp1); 93 j--; 94 double ans=0; 95 build(1,j,1); 96 for(i=1;i<=j;i++) 97 { 98 ans+=updata(1,link[i].down,link[i].up,link[i].flag,link[i].x); 99 } 100 printf("Test case #%d\n",++f); 101 102 printf("Total explored area: %.2lf\n\n",ans); 103 } 104 return 0; 105 }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。