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. Android 自己定义控件实现刮刮卡效果 真的就仅仅是刮刮卡么

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/40162163 , 本文出自:[张鸿洋的博客] 非常久以前也过一个html5的刮刮 ...

  2. 在全程Linux環境部署IBM Lotus Domino/Notes 8.5

    架設藍色巨人的協同合作訊息平台 在全程Linux環境部署IBM Lotus Domino/Notes 8.5 珊迪小姐 坊間幾乎所有探討IBM Domino/Notes的中文書籍,皆是以部署在Micr ...

  3. C++学习之模板特例化

    模板是C++中一个很重要的特性,写一份代码能用于多种数据类型(包括用户自定义类型).例如,STL的sort()函数可以用于多种数据类型的排序,类stack可以用作多种数据类型的栈.但是,如果我们想对特 ...

  4. Android 高仿 频道管理----网易、今日头条、腾讯视频 (能够拖动的GridView)附源代码DEMO

    距离上次公布(android高仿系列)今日头条 --新闻阅读器 (二) 相关的内容已经半个月了.近期利用空暇时间,把今日头条client完好了下.完好的功能一个一个所有实现后.就放整个源代码.开发的进 ...

  5. UVA - 10691 Subway

    题目大意:给定n个点.要求建造尽量少得铁路(从原点发射出的射线).使得全部点到铁路的最短距离小于d. 解题思路:题目能够转化成区间选点问题,即以极角来表示铁轨.然后计算出每一个区间可行的极角范围,进行 ...

  6. ios oc调用swift framework

    1.oc 调用swift /*oc调用swift, project name为DeomOC: 1.oc工程DemoOC中显式创建一个swift文件,生成DemoOC-Bridging-Header.h ...

  7. hdoj-1214-圆桌会议【逆序数】

    圆桌会议 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submissi ...

  8. node.js应用Redis初步

    node.js下使用Redis,首先: 1.有一台安装了Redis的服务器,当然,安装在本机也行 2.本机,也就是客户端,要装node.js 3.项目要安装nodejs_redis模块 注意第 3 点 ...

  9. CodeForces - 556D

    D. Case of Fugitive time limit per test 3 seconds memory limit per test 256 megabytes input standard ...

  10. POJ 2195 Going Home 最小费用流

    POJ2195 裸的最小费用流,当然也可以用KM算法解决,但是比较难写. 注意反向边的距离为正向边的相反数(因此要用SPFA) #include<iostream> #include< ...