hdu 1542 poj/pku 1151(线段树求面积并)
2011-09-19 15:39
489 查看
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542
http://poj.org/problem?id=1151
题意描述:给你n个矩形让你求这n个矩形的面积并
分析: 解决该题的方法很多,模拟和矩形切割都可以解决(当然是别人说的),鉴于学习线段树的需要,这里就用线段树解决此题,方法将平面上的矩形横着切割或者竖着切割成x块,然后求出每块的面积和即为答案,我们求的时候可以记住矩形所形成的每条竖直边,然后按照x坐标(当然亦可以按照y坐标排序,这个取决于你选择哪个坐标作为切割线)从小到大进行排序,那么相邻的两条竖直线的距离即使当期现成图形(注意这里可能不是一个矩形,可能是隔开的几个矩形)的长度,那么我们只需要求出每个图形需要的高度即可解决问题,那么解决这个高度就需要用线段树了,这就需要将矩形的边分为出边和入边了,当遇到入边的时候将线段树里插入该条线段,若遇到出边则在线段树里删除该条线段形成的影响,因为这里的坐标不是整数,所以必须先离散化。。。
线段树用来维护cover 、len ,前者表示当前线段被覆盖的次数,后者表示该区间被覆盖的长度,这里更新的时候由于数据弱,可以直接更新到底的进行维护(不建议使用),最好的还是找到该覆盖区间时就回溯更新,详情代码见
代码:
注释掉的部分为更新到底
http://poj.org/problem?id=1151
题意描述:给你n个矩形让你求这n个矩形的面积并
分析: 解决该题的方法很多,模拟和矩形切割都可以解决(当然是别人说的),鉴于学习线段树的需要,这里就用线段树解决此题,方法将平面上的矩形横着切割或者竖着切割成x块,然后求出每块的面积和即为答案,我们求的时候可以记住矩形所形成的每条竖直边,然后按照x坐标(当然亦可以按照y坐标排序,这个取决于你选择哪个坐标作为切割线)从小到大进行排序,那么相邻的两条竖直线的距离即使当期现成图形(注意这里可能不是一个矩形,可能是隔开的几个矩形)的长度,那么我们只需要求出每个图形需要的高度即可解决问题,那么解决这个高度就需要用线段树了,这就需要将矩形的边分为出边和入边了,当遇到入边的时候将线段树里插入该条线段,若遇到出边则在线段树里删除该条线段形成的影响,因为这里的坐标不是整数,所以必须先离散化。。。
线段树用来维护cover 、len ,前者表示当前线段被覆盖的次数,后者表示该区间被覆盖的长度,这里更新的时候由于数据弱,可以直接更新到底的进行维护(不建议使用),最好的还是找到该覆盖区间时就回溯更新,详情代码见
代码:
注释掉的部分为更新到底
/*#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=100005; const double eps=1e-8; struct line { double y1,y2,x; int id; }a[210]; struct node { int l,r; int cover; double len; }tree[4*N]; double y[2*N]; bool cmp(line a, line b) { return a.x<b.x; } double Max (double x, double y) { return x > y ? x:y; } void bulid(int rt, int l ,int r) { tree[rt].l=l; tree[rt].r=r; tree[rt].cover=0; tree[rt].len=0; if(l+1==r) return; int mid=(l+r)>>1; bulid(2*rt,l,mid); bulid(2*rt+1,mid,r); } int find (double x,int cnt) { int low = 0,high=cnt; while(low <=high) { int mid =(low+high)>>1; if(fabs(x-y[mid])<eps) return mid; if(x<y[mid]) high=mid-1; else low = mid+1; } } void insert(int rt, int l , int r) { if(tree[rt].l==l&&tree[rt].r==r&&l+1==r) { tree[rt].cover++; tree[rt].len=y[r]-y[l]; return; } int mid =(tree[rt].l+tree[rt].r)>>1; if(r <=mid) insert(2*rt,l,r); else if(l>=mid) insert(2*rt+1,l,r); else { insert(2*rt,l,mid);insert(2*rt+1,mid,r);} //if(!tree[rt].cover) //tree[rt].len=Max(tree[rt].len , tree[2*rt].len + tree[2*rt+1].len); tree[rt].len = tree[2*rt].len+tree[2*rt+1].len; } void del(int rt, int l, int r) { if(tree[rt].l==l&&r==tree[rt].r&&l+1==r) { tree[rt].cover--; if(tree[rt].cover==0) tree[rt].len=0; return; } int mid=(tree[rt].l+tree[rt].r)>>1; if(r <=mid) del(2*rt,l,r); else if(l>=mid) del(2*rt+1,l,r); else {del(2*rt,l,mid);del(2*rt+1,mid,r);} //if(!tree[rt].cover) //tree[rt].len=Max(tree[rt].len , tree[2*rt].len + tree[2*rt+1].len); tree[rt].len = tree[2*rt].len+tree[2*rt+1].len; } void print(int rt) { printf("%d %d %d\n",tree[rt].l ,tree[rt].r,tree[rt].cover); if(tree[rt].l+1==tree[rt].r) return ; print(2*rt); print(2*rt+1); } int main () { int n; int cas=1,i; double x1, y1, x2, y2; while(scanf("%d",&n)!=EOF) { if(n==0)break; int n1=0; for(i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); y[n1]=y1; a[n1].x=x1; a[n1].y1=y1; a[n1].y2=y2; a[n1++].id=1; //1表示入边 y[n1]=y2; a[n1].x=x2;a[n1].y1=y1; a[n1].y2=y2; a[n1++].id=-1; //-1表示出边 } sort(a,a+n1,cmp);//每条线从横坐标从小到大排序 // for(i=0;i<n1;i++) // printf("%.2lf %.2lf %.2lf %d\n",a[i].x,a[i].y1, a[i].y2,a[i].id); sort(y,y+n1); //离散化y坐标 int cnt; for(i=1,cnt=1;i<n1;i++)//将离散化的结果存放到y[]中 if(y[i]!=y[i-1]) y[cnt++]=y[i]; //for(i=0;i<cnt;i++) // cout << y[n1-1]<<endl; bulid(1,0,cnt-1); // print(1); //cout << y[n1-1] <<endl; double area=0; for(i=0;i<n1-1;i++) { int l=find(a[i].y1,cnt-1); int r=find(a[i].y2,cnt-1); if(a[i].id==1) insert(1,l,r); else if(a[i].id==-1) del(1,l,r); area+=tree[1].len*(a[i+1].x-a[i].x); } printf("Test case #%d\n",cas++); printf("Total explored area: %.2lf\n",area); printf("\n"); } return 0; } */ #include <iostream> #include <algorithm> #include<cstdio> using namespace std; struct node1 { double y1, y2; double x; int side; }line[210]; struct node { int l, r; //左边界和右边界 int count; //表示覆盖该区间的线段条数 double len; //线段覆盖区间的长度 }tree[1000]; int k; double y[210], yy[210]; bool cmp (node1 a, node1 b) { return a.x < b.x; } void creat(int root, int l, int r) { tree[root].l = l; tree[root].r = r; tree[root].count= 0; tree[root].len = 0; if (r-l > 1) { int mid = (l+r)/2; creat(2*root,l,mid); creat(2*root+1, mid, r); } } int find (double x) { int l = 0, r = k-1; while(l <= r) { int mid = (l+r)/2; if(y[mid] == x) return mid+1; if (x > y[mid]) l= mid+1; else r = mid-1; } } void update (int root) { if (tree[root].count) tree[root].len= (y[tree[root].r-1]-y[tree[root].l-1]);// 表示如果该区间节点有线段覆盖则覆盖长度为总区间长度 else if (tree[root].l+1== tree[root].r) tree[root].len= 0;//若没有线段覆盖且为根节点区间那么长度为0 else tree[root].len = tree[2*root].len + tree[2*root+1].len;//若没有线段覆盖到该非根节点,那么区间的长度就为其儿子的长度之和 } void insert (int root, int l, int r, int side) { if (l == tree[root].l&& r == tree[root].r) { tree[root].count += side; update(root); return ; } int mid = (tree[root].l+tree[root].r)/2; if (r <= mid) insert(2*root,l, r, side); else if (l >= mid) insert(2*root+1,l, r, side); else {insert(2*root,l,mid,side); insert(2*root+1,mid,r,side);} update(root);//回溯更新 } int main () { int n, t=1, i; double x1, x2, y1,y2; while(scanf ("%d", &n)!= EOF) { if (n== 0) break; k = 0; for (i = 0; i < n; i++) { scanf("%lf%lf%lf%lf",&x1, &y1,&x2, &y2); line[k].x = x1; line[k].y1 = y1; yy[k] = y1; line[k].side = 1; line[k++].y2 = y2; line[k].x = x2; line[k].y1 = y1; yy[k] = y2; line[k].side = -1; line[k++].y2 = y2; } sort (yy, yy+k); sort (line, line+k, cmp); y[0] = yy[0]; k = 1; for (i = 1; i < 2*n;i++) if(yy[i] != yy[i-1]) y[k++] = yy[i]; creat(1, 1, k); double sum = 0; for (i = 0; i < 2*n-1; i++) { y1 = find(line[i].y1); y2 = find(line[i].y2); insert (1, y1, y2, line[i].side); sum += (line[i+1].x - line[i].x)*tree[1].len; } printf("Test case #%d\n", t++); printf("Total explored area: %.2lf\n\n",sum); } return 0; }
相关文章推荐
- 线段树求矩形面积并 方法详解 (扫描线)HDU 1542 & HDU 3265 & POJ 1151
- poj 1151 && hdu 1542 求矩形面积并(线段树)
- hdu 1542&&poj 1151 Atlantis[线段树+扫描线求矩形面积的并]
- hdu 1542 & poj 1151 Atlantis 线段树扫描线求矩形面积并
- poj 1151 Atlantis / hdu 1542 线段树扫描线 矩形面积并
- 【codevs 3044】【HDU 1542】【poj 1151】矩形面积并 线段树+‘扫描线’
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
- poj 1151 hdu 1542 Atlantis 线段树扫描线,详细讲解,(*^__^*) 嘻嘻……
- HDU-1542/POJ-1151 Atlantis(矩形并面积--线段树+离散化)
- HDU 1542 [POJ 1151] Atlantis (矩形面积并)
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
- HDU 1542 / PKU 1151 (线段树 + 离散化 + 扫描线)
- HDOJ 1542 (POJ 1151) Atlantis 【线段树 离散化 扫描线 面积并】
- hdu1542 && pku 1151 Atlantis(面积并)
- poj 1151 & hdu 1542 Atlantis(线段树,扫描线)
- POJ 1151 & HDU 1542 Atlantis(扫描线模板 线段树 离散化)
- 【codevs 3044 矩形面积合并】【poj 1151 Atlantis】【hdu 1542 Atlantis】题意&题解&代码(c++)
- HDU 1542 & POJ 1151 Atlantis【线段树扫描线】
- poj 1151 && hdu 1542 离散化求矩形面积的并
- HDU - 1542 Atlantis(线段树扫描线求矩形面积并)