Atlantis

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11514    Accepted Submission(s): 4891

Problem Description
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
 
Input
The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.

The input file is terminated by a line containing a single 0. Don’t process it.

 
Output
For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.

Output a blank line after each test case.

 
Sample Input
2
10 10 20 20
15 15 25 25.5
0
 
Sample Output
Test case #1
Total explored area: 180.00
 
记得最开始学线段树的时候就看过这道题,我是完全懵逼的,本以为有生之年也不能弄懂这道题的思路,结果时至今日,总算是弄懂了传说中的扫描线。
 

struct segment       //这就是传说中的扫描线
{
  double l,r,h;     //l,r是左右端点,h为高度
  int f;     //上边f为-1,下边为1
}ss[2*MAXN];      //ss存的是所有矩形的上下边的信息

 
思路:
扫描线从下往上扫,所以离散化横坐标,因为我们每扫到一条边,就要update,即将这条边投影到总区间上,那么怎么update呢,线段上的点的坐标是double,所以我们离散化横坐标。用一个pos数组存储每个点的横坐标,下标为第几个点,我们将pos从小到大排序并去重,去重后的点个数为m,此时就可以建树了build(0,m-1,1);为什么这样建树,仔细一想应该能明白。
将ss(边)按高度升序排序,遍历,遍历到一条边,则在pos中搜索其左右端点在pos中的下标。如果是下边,将其投影到总区间,若是上边,则在总区间中将其对应下边的投影去掉。然后加上此次算出的一块面积。
 
 
注意:
扫描线段时r-1:int R=search(s[i].l,hash,m)-1; 
计算底边长时r+1:if(mark[n])sum[n]=hash[right+1]-hash[left]; 
解释:假设现在有一个线段左端点是l=0,右端点是r=m-1 
则我们去更新的时候,会算到sum[1]=hash[mid]-hash[left]+hash[right]-hash[mid+1] 
这样的到的底边长sum是错误的,why?因为少算了mid~mid+1的距离,由于我们这利用了 
离散化且区间表示线段,所以mid~mid+1之间是有长度的,比如hash[3]=1.2,hash[4]=5.6,mid=3 
所以这里用r-1,r+1就很好理解了   
#include<cstdio>
#include<set>
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<string>
#include<cstring>
using namespace std;
#define MAXN 105
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1 struct segment
{
double l,r,h;
int f;
}ss[*MAXN]; struct Node
{
int l,r;
int cnt;
double len;
int mid()
{
return (l+r>>);
}
}tt[*MAXN*]; double pos[*MAXN];
int nums; bool cmp(segment a,segment b)
{
return a.h<b.h;
} void build(int l,int r,int rt)
{
tt[rt].l=l;
tt[rt].r=r;
tt[rt].cnt=;
tt[rt].len=;
if(l==r)
return;
int mid=(l+r)>>;
build(lson);
build(rson);
} int binary(double key,int l,int r)
{
while(l<=r)
{
int mid=(l+r)>>;
if(pos[mid]==key)
return mid;
else if(key<pos[mid])
r=mid-;
else
l=mid+;
}
return -;
} void get_len(int rt)
{
if(tt[rt].cnt)
tt[rt].len=pos[tt[rt].r+]-pos[tt[rt].l];
else if(tt[rt].l==tt[rt].r)
tt[rt].len=;
else
tt[rt].len=tt[rt<<].len+tt[rt<<|].len;
} void update(int l,int r,int val,int rt)
{
if(tt[rt].l==l&&tt[rt].r==r)
{
tt[rt].cnt+=val;
get_len(rt);
return;
}
int mid=tt[rt].mid();
if(r<=mid)
update(l,r,val,rt<<);
else if(l>mid)
update(l,r,val,rt<<|);
else
{
update(l,mid,val,rt<<);
update(mid+,r,val,rt<<|);
}
get_len(rt);
} int main()
{
int cas=;
int n;
while(scanf("%d",&n)!=EOF&&n)
{
nums=;
for(int i=;i<n;i++)
{
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
ss[nums].l=x1;ss[nums].r=x2;ss[nums].h=y1;ss[nums].f=-;
ss[nums+].l=x1;ss[nums+].r=x2;ss[nums+].h=y2;ss[nums+].f=;
pos[nums]=x1;pos[nums+]=x2;
nums+=;
}
sort(ss,ss+nums,cmp);
sort(pos,pos+nums);
int m=;
for(int i=;i<nums;i++)
if(pos[i]!=pos[i-])
pos[m++]=pos[i];
build(,m-,);
double ans=;
for(int i=;i<nums;i++)
{
int l=binary(ss[i].l,,m-);
int r=binary(ss[i].r,,m-)-;
update(l,r,ss[i].f,);
ans+=(ss[i+].h-ss[i].h)*tt[].len;
}
printf("Test case #%d\n",++cas);
printf("Total explored area: %.2f\n\n",ans);
}
return ;
}
 

HDU_1542_线段树【扫描线】的更多相关文章

  1. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  2. Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)

    题目链接:http://codeforces.com/contest/522/problem/D 题目大意:  给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...

  3. 【POJ-2482】Stars in your window 线段树 + 扫描线

    Stars in Your Window Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11706   Accepted:  ...

  4. HDU 4419 Colourful Rectangle --离散化+线段树扫描线

    题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...

  5. BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤

    3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...

  6. BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞

    看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...

  7. hdu 5091(线段树+扫描线)

    上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...

  8. POJ1151+线段树+扫描线

    /* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...

  9. POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]

    题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...

  10. HDU 5107 线段树扫描线

    给出N个点(x,y).每一个点有一个高度h 给出M次询问.问在(x,y)范围内第k小的高度是多少,没有输出-1 (k<=10) 线段树扫描线 首先离散化Y坐标,以Y坐标建立线段树 对全部的点和询 ...

随机推荐

  1. mongodb分片集搭建

    拓扑图如下: 从图中可以看到有四个组件:mongos.config server.shard.replica set. mongos,数据库集群请求的入口,所有的请求都通过mongos进行协调,不需要 ...

  2. Hadoop2.0安装之非HA版

    主要步骤跟Hadoop1.0(1.0安装地址)一致,主要在配置这块有更改 安装 下载地址:http://archive.apache.org/dist/hadoop/core/hadoop-2.6.5 ...

  3. 美河LINUX 内核学习视频

    Linux内核从原理到代码详解 培训视频 Linux内核源码研读与实战演练 [7.10][美河资料发布小组@aipepsi][linux内核分析视频教程] 炼数成金Linux内核探秘 [11.23][ ...

  4. stack、queue实现

    //SGI STL以deque作为缺省情况下的stack底部结构,stack没有迭代器,不提供遍历功能 //queue的实现类似stack,也是以deque作为缺省底层结构 template < ...

  5. uboot arp地址解析

    common/cmd_cache.c int do_getmac(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) {     //usend d ...

  6. HDU 3008 DP

    基础DP题 打BOSS  BOSS和自己都有100点血.玩家先手 每回合能够选择施放技能攻击(耗蓝,共n种)或者普通攻击(不耗蓝,伤害为1),BOSS每回合会攻击自己q点血,每回合自己会恢复t点法力 ...

  7. C++简单版BitSet求解大量数据是否存在莫个数

    #include <iostream> using namespace std; template<int N> class BitSet { public: BitSet() ...

  8. 数据结构之---C语言实现图的邻接表存储表示

    // 图的数组(邻接矩阵)存储表示 #include <stdio.h> #include <stdlib.h> #include <string.h> #defi ...

  9. cached

    /proc/sys/vm/ 关于Linux cached内存简析 - CSDN博客 http://blog.csdn.net/fox_hacker/article/details/41351687 [ ...

  10. Luogu3403跳楼机

    https://zybuluo.com/ysner/note/1099616 题面 给你三个数\(x\),\(y\),\(z\),问你能够凑出多少个[1,\(h\)]之间的数. 解析 处理出\(y\) ...