hdu 1255 覆盖的面积 (线段树,离散化+扫描线)
来源:互联网 发布:win7仿mac主题 编辑:程序博客网 时间:2024/05/16 04:27
题目链接:传送门
覆盖的面积
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6058 Accepted Submission(s): 3051
Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用scanf读入数据.
Output
对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
Sample Input
2
5
1 1 4 2
1 3 3 7
2 1.5 5 4.5
3.5 1.25 7.5 4
6 3 10 7
3
0 0 1 1
1 0 2 1
2 0 3 1
Sample Output
7.63
0.00
没有做过扫描线的可先做 hdu 1542 Atlantis 传送门
思路:先离散化,更新时,更新到被覆盖的区域,或者更新到点,然后在进行扫描线,就行了。
#include<stdio.h>#include<string.h>#include<map>#include<algorithm>using namespace std;#define N 1009map<double,int>q;struct node{ int l,r;//区间范围 double chang;//被二次覆盖的区间长度 int inq;//区间被覆盖了多少次} tree[N*10];struct nodee{ double h1,h2;//矩形的两个横坐标 double x;//矩形的左右两边,边的纵坐标 int inq;//是左边的边(1),还是右边的边(-1) void set_date(double a,double b,double c,int d) { h1=a,h2=b,x=c,inq=d; } bool operator<(const nodee &q) const { return x<q.x; }} dis[N*2];double a[N*2];void build(int num,int l,int r)//建树{ tree[num].l=l; tree[num].r=r; tree[num].inq=0; tree[num].chang=0; if(l==r) return ; int mid=(l+r)>>1; build(num<<1,l,mid); build(num<<1|1,mid+1,r);}void up(int num){ if(tree[num].inq>1)//被覆盖两次以上才记录长度 tree[num].chang=a[tree[num].r+1]-a[tree[num].l]; else if(tree[num].l==tree[num].r)//没有被覆盖两次以上 tree[num].chang=0; else //为了最后能将长度,汇总到tree[1].chang。 tree[num].chang=tree[num<<1].chang+tree[num<<1|1].chang;}void update(int num,int x,int y,int p)//更新{ int l=tree[num].l,r=tree[num].r,mid=(l+r)>>1; if(x<=l&&r<=y) { if(tree[num].inq)//该区间被覆盖过 { tree[num].inq+=p; up(num); return ; } if(l==r)//该区间没被覆盖过,到达了尽头 { tree[num].inq+=p; return ; } } if(x<=mid) update(num<<1,x,y,p); if(y>mid) update(num<<1|1,x,y,p); up(num);}int main(){ int n,t; scanf("%d",&t); while(t--) { scanf("%d",&n); q.clear(); memset(a,0,sizeof(a)); double x1,y1,x2,y2; int m=0; for(int i=0; i<n; i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); a[m]=x1; dis[m++].set_date(x2,x1,y1,1); a[m]=x2; dis[m++].set_date(x2,x1,y2,-1); } sort(dis,dis+m); sort(a,a+m); int mm=unique(a,a+m)-a;//离散化,去重 build(1,0,mm-1); for(int i=0; i<mm; i++)//离散化,用map数组记录离散化后的所对应的值 q[a[i]]=i; double sum=0; for(int i=0; i<m-1; i++)//扫描线 { update(1,q[dis[i].h2],q[dis[i].h1]-1,dis[i].inq); sum+=(dis[i+1].x-dis[i].x)*tree[1].chang; } printf("%.2lf\n",sum); } return 0;}/*932 0 4 50 2 3 42 3 3 7*/
较简单的一种想法:
#include<stdio.h>#include<string.h>#include<map>#include<algorithm>using namespace std;#define N 1009map<double,int>q;struct node{ int l,r;//区间范围 int inq;//区间被覆盖了多少次} tree[N*10];struct nodee{ double h1,h2;//矩形的两个横坐标 double x;//矩形的左右两边,边的纵坐标 int inq;//是左边的边(1),还是右边的边(-1) void set_date(double a,double b,double c,int d) { h1=a,h2=b,x=c,inq=d; } bool operator<(const nodee &q) const { return x<q.x; }} dis[N*2];double a[N*2];void build(int num,int l,int r)//建树{ tree[num].l=l; tree[num].r=r; tree[num].inq=0; if(l==r) return ; int mid=(l+r)>>1; build(num<<1,l,mid); build(num<<1|1,mid+1,r);}void doo(int num){ if(tree[num].inq) { int h=tree[num].inq; tree[num<<1].inq+=h; tree[num<<1|1].inq+=h; tree[num].inq=0; }}void update(int num,int x,int y,int p)//更新,每个区间被覆盖了多少次{ int l=tree[num].l,r=tree[num].r,mid=(l+r)>>1; if(x<=l&&r<=y) { tree[num].inq+=p; return ; } doo(num); if(x<=mid) update(num<<1,x,y,p); if(y>mid) update(num<<1|1,x,y,p);}double query(int num)//查找长度{ int l=tree[num].l,r=tree[num].r,mid=(l+r)>>1; if(tree[num].inq>1) return a[r+1]-a[l]; if(l==r) return 0; doo(num); double sum=0; sum+=query(num<<1)+query(num<<1|1); return sum;}int main(){ int n,t; scanf("%d",&t); while(t--) { scanf("%d",&n); q.clear(); memset(a,0,sizeof(a)); double x1,y1,x2,y2; int m=0; for(int i=0; i<n; i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); a[m]=x1; dis[m++].set_date(x2,x1,y1,1); a[m]=x2; dis[m++].set_date(x2,x1,y2,-1); } sort(dis,dis+m); sort(a,a+m); int mm=unique(a,a+m)-a;//离散化,去重 build(1,0,mm-1); for(int i=0; i<mm; i++)//离散化,用map数组记录离散化后的所对应的值 q[a[i]]=i; double sum=0; for(int i=0; i<m-1; i++)//扫描线 { update(1,q[dis[i].h2],q[dis[i].h1]-1,dis[i].inq); double h=query(1);//查找被覆盖两次的区间范围 sum+=(dis[i+1].x-dis[i].x)*h; } printf("%.2lf\n",sum); } return 0;}
阅读全文
0 0
- HDU-1255 覆盖的面积(线段树扫描线+离散化+改进后超快的算法)
- hdu 1255 覆盖的面积(线段树+离散化+扫描线)
- HDU 1255 覆盖的面积(线段树+离散化+扫描线)
- HDU 1255 覆盖的面积(线段树+扫描线+离散化)
- hdu 1255 覆盖的面积 (线段树,离散化+扫描线)
- HDU-1255 覆盖的面积(线段树扫描线模板+离散化+加点修改题)
- 覆盖的面积(线段树+扫描线+离散化)
- HDU 1255 覆盖的面积[离散化 + 扫描线 + 线段树]
- HDU 1255 覆盖的面积 (线段树 + 离散化 + 扫描线)
- hdu 1255 覆盖的面积 线段树+离散化+扫描线
- HDU 1255 覆盖的面积 线段树+扫描线+离散化
- HDU 1255 覆盖的面积(离散化+线段树)
- hdu1255 覆盖的面积 扫描线+线段树+离散化
- hdu1255--覆盖的面积(线段树+离散化+扫描线)
- HDU1255覆盖的面积(线段树+离散化+扫描线)
- HDU 1255 覆盖的面积(线段树+扫描线)
- HDU 1255 覆盖的面积(线段树扫描线)
- HDU 1255 覆盖的面积 (线段树扫描线)
- AfxBeginThread参数传递
- 2017.8.11
- POJ
- SpringMVC第五篇【方法返回值、数据回显、idea下配置虚拟目录、文件上传】
- java 类的实例 new一个对象初始化顺序
- hdu 1255 覆盖的面积 (线段树,离散化+扫描线)
- Mosca认证与授权
- 面对不靠谱的需求,软件开发行业的产品经理该如何解决
- 1025. 反转链表
- 浅谈jsp、freemarker、velocity区别
- 机器学习笔记——Scikit-learn库中的数据预处理(一)
- 微服务部署:蓝绿部署、滚动部署、灰度发布、金丝雀发布
- 在header中添加LOGO
- 摄像头P2P软件提供,完美解决打洞及音视频、用户码传输问题。