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. Ubuntu 16.04安装BleachBit清理系统垃圾文件

    在LInux下不同于Windows会产生系统垃圾,但是Linux会产生安装软件时的依赖包,比如卸载一个软件,其依赖包是不会删除的.但是可以通过以下命令解决: #清理旧版本的软件缓存 sudo apt- ...

  2. [Vue-rx] Switch to a Function which Creates Observables with Vue.js and Rxjs

    Wrapping the creation of an Observable inside of a Function allows you delay the creation of the Obs ...

  3. 数据库数据在Java占用内存简单估算

    数据库数据在Java占用内存简单估算 结论: 1.数据库记录放在JAVA里,用对象(ORM一般的处理方式)须要4倍左右的内存空间.用HashMap这样的KV保存须要10倍空间; 2.假设你主要数据是t ...

  4. C#程序猿学习 Python

    孙广东  2016.1.1 交互: C# 运行Python代码: http://stackoverflow.com/questions/11779143/run-a-python-script-fro ...

  5. LeetCode 237. Delete Node in a Linked List (在链表中删除一个点)

    Write a function to delete a node (except the tail) in a singly linked list, given only access to th ...

  6. bzoj 2333 [SCOI2011]棘手的操作 —— 可并堆

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2333 稍微复杂,参考了博客:http://hzwer.com/5780.html 用 set ...

  7. 1章 课程介绍 IDEA介绍演示与安装 IDEA安装

  8. mysql大数据的分表

    在实际业务运作中,我们经常遇到一个表中数据量过大的问题,这样的话,问题就来了.如何将一个表中的数据均衡的放到多个表中? 我的建议是,新建一个表,但是只有一个自增的id字段,将其作为分表的依据.有大数据 ...

  9. Java Itext 生成PDF文件

    利用Java Itext生成PDF文件并导出,实现效果如下: PDFUtil.java package com.jeeplus.modules.order.util; import java.io.O ...

  10. 【学习笔记】OI玄学道—代码坑点

    [学习笔记]\(OI\) 玄学道-代码坑点 [目录] [逻辑运算符的短路运算] [\(cmath\)里的贝塞尔函数] 一:[逻辑运算符的短路运算] [运算规则] && 和 || 属于逻 ...