HDU - 1542 Atlantis(线段树求面积并)
https://cn.vjudge.net/problem/HDU-1542
题意
求矩形的面积并
分析
点为浮点数,需要离散化处理。
给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1)、(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1;另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1。根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序。插入某跟线段的时候,只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的x定位 - 上一线段的x定位)*(该区间的大小)。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define eps 0.0000000001
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = + ;
const int maxm = + ;
const int mod = ; int n;
double y[maxn];
struct LINE{
double x;
double y1,y2;
int flag;
bool operator <(const LINE &a)const{
return x<a.x;
}
}line[maxn];
struct ND{
double l,r;
double x;
int cover;
bool flag;
}tree[maxn<<];
void build(int rt,int l,int r){
tree[rt].l=y[l];
tree[rt].r=y[r];
tree[rt].x=-;
tree[rt].flag=false;
tree[rt].cover=; //表示该区间有多少线段,左加右减
if(l+==r){//叶结点
tree[rt].flag=true;
return;
}
int mid = (l+r)>>;
build(rt<<,l,mid);
build(rt<<|,mid,r);//这里是mid
}
double insert_query(int rt,double x,double l,double r,int flag){
if(l>=tree[rt].r||r<=tree[rt].l) return ; //检验区间合法
if(tree[rt].flag){
if(tree[rt].cover>){
double ans=(x-tree[rt].x)*(tree[rt].r-tree[rt].l);
tree[rt].x=x;
tree[rt].cover+=flag;
return ans;
}else{
tree[rt].x=x;
tree[rt].cover+=flag;
return ;
}
}
return insert_query(rt<<,x,l,r,flag)+insert_query(rt<<|,x,l,r,flag);
}
int main() {
#ifdef LOCAL
freopen("in.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int T,cas=;
// scanf("%d",&T);
while(~scanf("%d",&n)&&n){
int cnt=-;
double x1,x2,y1,y2;
for(int i=;i<n;i++){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
y[++cnt]=y1;
line[cnt].x=x1;
line[cnt].y1=y1;
line[cnt].y2=y2;
line[cnt].flag=;//左边
y[++cnt]=y2;
line[cnt].x=x2;
line[cnt].y1=y1;
line[cnt].y2=y2;
line[cnt].flag=-;//右边
}
sort(y,y++cnt);
sort(line,line++cnt);
build(,,cnt);
double area=;
for(int i=;i<=cnt;i++){
area+=insert_query(,line[i].x,line[i].y1,line[i].y2,line[i].flag);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",cas++,area);
}
return ;
}
还有一种高端做法。
该方法同样需要在线段树中定义一个cover域,表示该线段区间目前被覆盖的线段数目。另外再加一个len域,表示该区间可用于与下一线段求并面积的y坐标区间长度。然后利用简单的dp,将所有信息集中于tree[1].len上,这样便不用想第一种方法那样每次都求到叶子线段,大大节约了时间,并且代码也少了很多。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std; struct node
{
int l;
int r;
int cover;
double len;
}; node tree[];
double yy[];
int n,len; struct Line
{
double y_down;
double y_up;
double x;
int cover;
}; Line line[]; int cmp(Line a,Line b)
{
return a.x<b.x;
} int find(double x)
{
int l=,r=len,mid;
while(l<=r)
{
mid=(l+r)/;
if(yy[mid]==x)
return mid;
if(yy[mid]<x)
l=mid+;
else
r=mid-;
}
return l;
} void build(int i,int l,int r)
{
tree[i].l=l;
tree[i].r=r;
tree[i].cover=;
tree[i].len=;
if(l+==r)
return;
int mid=(l+r)/;
build(*i,l,mid);
build(*i+,mid,r);
} void fun(int i)
{
if(tree[i].cover)
tree[i].len=yy[tree[i].r]-yy[tree[i].l]; //如果cover大于1,那么整段都可用于与下一线段求并面积
else if(tree[i].l+==tree[i].r) //叶子线段
tree[i].len=;
else
tree[i].len=tree[*i].len+tree[*i+].len; //很简单的dp
} void updata(int i,int l,int r,int cover)
{
if(tree[i].l>r || tree[i].r<l)
return;
if(tree[i].l>=l && tree[i].r<=r)
{
tree[i].cover+=cover;
fun(i);
return;
}
updata(*i,l,r,cover);
updata(*i+,l,r,cover);
fun(i);
} int main()
{
double x1,y1,x2,y2;
int i,m,a,b,cas=;
freopen("in.txt","r",stdin);
while(scanf("%d",&n)== && n)
{
m=;
for(i=;i<n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
yy[m]=y1;
line[m].cover=;
line[m].x=x1;
line[m].y_down=y1;
line[m++].y_up=y2; yy[m]=y2;
line[m].cover=-;
line[m].x=x2;
line[m].y_down=y1;
line[m++].y_up=y2;
}
sort(yy,yy+m);
len=;
for(i=;i<m;i++)
{
if(yy[i-]!=yy[i])
yy[len++]=yy[i];
}
len--;
build(,,len);
sort(line,line+m,cmp);
double ans=;
printf("Test case #%d\n",cas++);
for(i=;i<m-;i++)
{
a=find(line[i].y_down);
b=find(line[i].y_up);
updata(,a,b,line[i].cover);
ans+=tree[].len*(line[i+].x-line[i].x); //tree[1].len已经保留了整个树与line[i+1]所能求并面积的长度
}
printf("Total explored area: %0.2lf\n\n",ans);
}
return ;
}
HDU - 1542 Atlantis(线段树求面积并)的更多相关文章
- POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
题意:给出矩形两对角点坐标,求矩形面积并. 解法:线段树+离散化. 每加入一个矩形,将两个y值加入yy数组以待离散化,将左边界cover值置为1,右边界置为2,离散后建立的线段树其实是以y值建的树,线 ...
- HDU 1542 Atlantis(线段树面积并)
描述 There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. S ...
- HDU 1542 - Atlantis - [线段树+扫描线]
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Time Limit: 2000/1000 MS (Java/Others) Memory Li ...
- hdu 1542 Atlantis (线段树扫描线)
大意: 求矩形面积并. 枚举$x$坐标, 线段树维护$[y_1,y_2]$内的边是否被覆盖, 线段树维护边时需要将每条边挂在左端点上. #include <iostream> #inclu ...
- hdu 1542 Atlantis(线段树,扫描线)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- HDU 1542.Atlantis-线段树求矩形面积并(离散化、扫描线/线段树)-贴模板
好久没写过博客了,这学期不是很有热情去写博客,写过的题也懒得写题解.现在来水一水博客,写一下若干年前的题目的题解. Atlantis Time Limit: 2000/1000 MS (Java/Ot ...
- POJ 1151 Atlantis 线段树求矩形面积并 方法详解
第一次做线段树扫描法的题,网搜各种讲解,发现大多数都讲得太过简洁,不是太容易理解.所以自己打算写一个详细的.看完必会o(∩_∩)o 顾名思义,扫描法就是用一根想象中的线扫过所有矩形,在写代码的过程中, ...
- HDU - 1255 覆盖的面积 (线段树求面积交)
https://cn.vjudge.net/problem/HDU-1255 题意 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 分析 求面积并的题:https://www.cnbl ...
- hdu 1542 Atlantis(段树&扫描线&面积和)
Atlantis Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
随机推荐
- 【Sichuan 2017D】Dynamic Graph
题意 300个点的无环图,开始都是白色,每次改变某个节点的颜色(黑/白),问有多少对白点之间存在只有白点的路径. 题解 类似floyd,求出两点之间的路径条数.然后白到黑就删去对应路径,黑到白就增加对 ...
- UOJ277【清华集训2016】定向越野(计算几何,最短路)
UOJ题目传送门 显然最优的路径只会经过若干条两个圆的公切线和若干段圆弧 为了方便,把起点终点看成两个半径为\(0\)的圆也行. 最烦的就是算两个圆的公切线了,一共有四条 对于靠外面的两条,我们把切线 ...
- GCD HDU - 1695(容斥原理)
要求从满足gcd(x, y) = k的对数,其中x属于[1, n], y属于[1, m] gcd(x, y) = k ==>gcd(x/k, y/k) =1 x/k属于[1, n/k], y/k ...
- 洛谷 P5020 【货币系统】
谁说这一定要排序的,这就是个装满背包嘛 \({f[i]}\) 表示 \(i\) 面值最多能被几张钱表示 则若其不能被表示 \(f[i]=-inf\) 能表示且只有它自己则 \(f[i]=1\) 初始化 ...
- 课后选做题:MyCP
目录 CP命令了解 MyCP实现 CP命令了解 作用:cp指令用于复制文件或目录,如同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前面指定的所有文件或目录复制到此目录中.若 ...
- 编写高质量代码:改善Java程序的151个建议 --[26~36]
提防包装类型的null值 public static int testMethod(List<Integer> list) { int count = 0; for (Integer i ...
- go语言通道详解
https://www.ardanlabs.com/blog/2017/10/the-behavior-of-channels.html Introduction When I started to ...
- Electron一学习资源收集和练习demo
1.近日为了做项目查资料学习electron,简直头都要炸了,就官方的electron-quick-start的例子进行了基本的练习之后,不断的查资料终于发现一些有用的demo来看源代码学习,一遍看代 ...
- QTREE6&&7 - Query on a tree VI &&VII
树上连通块 不用具体距离,只询问连通块大小或者最大权值 可以类比Qtree5的方法,但是记录东西很多,例如子树有无0/1颜色等 一个trick,两个LCT分离颜色 每个颜色在边上. 仅保留连通块顶部不 ...
- LINQ的基础使用方法
//新建一个项目 //项目下新建一个App_Code文件夹 //在文件夹内添加一个LINQ TO SQL,这个操作就相当于创建了一个实体类 //连接数据库后把表拖入到服务器资源管理器中 //创建数据访 ...