hdu 1255(线段树 扫描线) 覆盖的面积

http://acm.hdu.edu.cn/showproblem.php?pid=1255

典型线段树辅助扫描线,顾名思义扫描线就是相当于yy出一条直线从左到右(也可以从上到下)扫描过去,此时先将所有的横坐标和纵坐标排序

因为是从左到右扫描,那么横坐标应该离散化一下

当扫描线依次扫描的时候,依次扫描到的纵区间在线段树中查找,依据是上边还是下边记录,上边就是-1,下边就是+1,

如果某区间记录值为0的时候,代表没有被覆盖,为1的时候代表覆盖一次,为2代表覆盖两次(不会出现为负数的情况)

最后将依次扫描的覆盖两次的纵区间长度乘以以此的横坐标的和就行

所以http://acm.hdu.edu.cn/search.php?action=listproblem hdu1542 就在稍微改改这题的代码就行了

code

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 using namespace std;
  5 struct node{
  6     double x,y1,y2;
  7     double flag;
  8 };
  9 node num[2001];
 10 double a[2001];
 11 bool cmp(node q,node w){return q.x<w.x;}
 12 struct point {
 13      int l,r,mark;
 14      double lf,rf;
 15      double once; //覆盖一次
 16      double twice;//覆盖两次
 17 };
 18 point tree[2001*4];
 19 void build(int i,int left,int right)
 20 {
 21     tree[i].l=left,tree[i].r=right;
 22     tree[i].once=tree[i].twice=0;
 23     tree[i].lf=a[left];
 24     tree[i].rf=a[right];
 25     if (left+1==right) return ;
 26     int mid=(left+right)/2;
 27     build(i*2,left,mid);
 28     build(i*2+1,mid,right);
 29 }
 30 void find(int i)
 31 {
 32     if (tree[i].mark>=2)
 33     {
 34         tree[i].twice=tree[i].once=tree[i].rf-tree[i].lf;
 35         return;
 36     }
 37     else if (tree[i].mark==1)
 38     {
 39         tree[i].once=tree[i].rf-tree[i].lf;
 40         if (tree[i].l+1==tree[i].r) tree[i].twice=0;
 41         else tree[i].twice=tree[i*2].once+tree[i*2+1].once;
 42     }
 43     else
 44     {
 45         if(tree[i].l+1==tree[i].r)
 46             tree[i].once=tree[i].twice=0;
 47         else
 48         {
 49             tree[i].once=tree[i*2].once+tree[i*2+1].once;
 50             tree[i].twice=tree[i*2].twice+tree[i*2+1].twice;
 51         }
 52     }
 53 }
 54 void update(int i,node g)
 55 {
 56     //printf("***%d***\n",i);
 57     if (g.y1==tree[i].lf&&g.y2==tree[i].rf)
 58     {
 59         tree[i].mark+=g.flag;
 60         find(i); //更新区间
 61         return ;
 62     }
 63     if (g.y2<=tree[i*2].rf) update(i*2,g);
 64     else if (g.y1>=tree[i*2+1].lf) update(i*2+1,g);
 65     else
 66     {
 67         node temp=g;
 68         temp.y2=tree[i*2].rf;
 69         update(i*2,temp);
 70         temp=g;
 71         temp.y1=tree[i*2+1].lf;
 72         update(i*2+1,temp);
 73     }
 74     find(i);
 75 }
 76 int main()
 77 {
 78     int t,n,i,k;
 79     double x1,x2,y1,y2,ans;
 80     while (~scanf("%d",&k))
 81     {
 82         while (k--)
 83         {
 84             scanf("%d",&n);
 85             t=1;
 86             while (n--)
 87             {
 88                 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
 89                 num[t].x=x1,num[t].y1=y1,num[t].y2=y2;
 90                 num[t].flag=1;a[t]=y1;
 91                 t++;
 92                 num[t].x=x2,num[t].y1=y1,num[t].y2=y2;
 93                 num[t].flag=-1;a[t]=y2;
 94                 t++;
 95             }
 96             sort(num+1,num+t,cmp);
 97             sort(a+1,a+t);
 98             ans=0;
 99             build(1,1,t-1);
100             //printf("-1\n");
101             update(1,num[1]);
102             for (i=2;i<t;i++)
103             {
104                 ans+=tree[1].twice*(num[i].x-num[i-1].x);
105                 update(1,num[i]);
106             }
107             printf("%.2lf\n",ans);
108         }
109     }
110     return 0;
111 }
时间: 2024-08-06 20:49:05

hdu 1255(线段树 扫描线) 覆盖的面积的相关文章

hdu 1255 覆盖的面积 线段树扫描线求重叠面积

稀里糊涂打完了没想到1A了,心情还是很舒畅的,c和c++的四舍五入还是四舍六入遇积进位遇偶舍,我感觉很混乱啊,这道题我输出的答案是7.62,也就是遇偶舍了,可是我就手动处理一下进位问题,发现0.005 系统自动进位0.01了,尼玛啊,我一下子就混乱了,不是遇偶舍么,0也是偶数啊,怎么就进位了呢.最后我就不手动处理进位问题了,直接0.2lf%,虽然我输出的结果是7.62,但是提交也过了 这道题和poj1151,hdu1542差不多,扫描线详细讲解http://blog.csdn.net/young

线段树+扫描线求矩形面积的并

POJ 1151 Atlantis(线段树+扫描线) 参考博客https://blog.csdn.net/lwt36/article/details/48908031 上面博客的原理讲解非常清楚 在这我只对代码的模板分层讲解 一些基础的 #include <iostream> #include <cstdio> #include <string.h> #include <algorithm> #include <cmath> #define ls

HDU 5107 线段树扫描线

给出N个点(x,y),每个点有一个高度h 给出M次询问,问在(x,y)范围内第k小的高度是多少,没有输出-1 (k<=10) 线段树扫描线 首先离散化Y坐标,以Y坐标建立线段树 对所有的点和询问进行离线操作,将询问和点按照x,y的大小排序,从左向右,从下向上,对于相同的(x,y)插入点在询问点之前 线段树的每个节点维护10个高度,每次询问[0,mark[i].y]的第mark[i].h高的值即可 #include "stdio.h" #include "string.h

HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11551    Accepted Submission(s): 4906 Problem Description There are several ancient Greek texts that contain descriptions of the fabled

HDU 3265 Posters(线段树扫描线&#183;矩形框面积并)

题意  把一些矩形海报挖去一部分小矩形贴在指定位置  问最后海报覆盖的面积 一个矩形框可以分割成4个独立的小矩形  然后就能用扫描线求面积并了 #include <cstdio> #include <algorithm> using namespace std; const int N = 100005, M = N << 2; typedef long long ll; struct SLine { int x, y1, y2, flag; SLine() {}; S

HDU 5091 线段树扫描线

给出N个点,和一个w*h的矩形 给出N个点的坐标,求该矩形最多可以覆盖多少个点 对每个点point(x,y)右边生成对应的点(x+w,y)值为-1: 纵向建立线段树,从左到右扫描线扫一遍,遇到点则用该点的权值更新区间(y,y+h) #include "stdio.h" #include "string.h" #include "algorithm" using namespace std; struct Mark { int x,y,s; }ma

hdu 1542 线段树+扫描线

啦啦啦~继续学算法 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7349    Accepted Submission(s): 3231 Problem Description There are several

hdu 1264 线段树+扫描线

说实话  真是水题   题目给的数据太小  都不用离散化      之前用离散化处理一个类似的题 这道题是给你几个矩形    让你求覆盖面积    重复的只算一次 做完之后被坑了        题目说输入左下角和右下角坐标    但是     左上角和右下角也有可能   只要是对角就行    所有得线处理一下 #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h>

HDU 1542 线段树+扫描线+离散化

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 8327    Accepted Submission(s): 3627 Problem Description There are several ancient Greek texts that contain descriptions of the fabled is