POJ - 1177 线段树
POJ - 1177 扫描线
这道题也算是一道扫描线的经典题目了。
只不过这道题是算周长,非常有意思的一道题。我们已经知道了,一般求面积并,是如何求的,现在我们要把扫描线进行改造一下,使得能算周长。
我们大致考虑一下图像上是如何实现的:
这样一个图我们要如何求他的面积?

我们把轮廓画出来

我们把扫描线画出来

我们发现
从上到下我们竖直方向的长度,是每条线高度差*2*线段树的连续的段数目。
从上到下我们水平方向的长度,是横线的长度 = 现在这次总区间被覆盖的长度和上一次总区间被覆盖的长度之差的绝对值。
这样我们就找到解决的办法,维护就非常容易了,本题范围比较小,因此不用离散化,直接区间建树,节点维护4个值,
Len:区间内部被覆盖一次以上的长度
S:区间内被完全覆盖的次数
这个是常规操作。
然后维护区间内部,连续区间(每个之间是隔离的)的个数
然后两个lc,rc,代表区间左端点和右端点是否在连续区间内(合并区间的时候有用)
这样就行了。
然后考虑子节点往上pushup的情况,
首先区间被完全填满,那么len等于区间长度,lc,rc,num都是1。
如果到叶节点,都是0
否则,len,rc,lc,的长度由两个儿子节点提供,需要注意的是,num的情况是由两个儿子提供,如果左儿子的右边界和右儿子的左边界都是在连续的区间中,那么这个区间会被合成为1个区间,从而个数需要减1.
最后常规的操作即可。
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
const int N = ;
const int X = ;
const int inf = <<;
inline int L(int r){return r<<;};
inline int R(int r){return r<<|;};
inline int MID(int l,int r){return (l+r)>>;};
struct Edge{
int l,r;
int h;
int f;
}line[N*];
struct node{
int l,r,len,s,num;
//num这个区间有多少不连续的线段
bool lc,rc;//区间左右端点是否被覆盖
}tree[X<<];
bool cmp(Edge a,Edge b)
{
return a.h<b.h;
}
void pushup(int root)
{
if (tree[root].s){
tree[root].len=tree[root].r-tree[root].l+;//没有离散化
tree[root].rc=tree[root].lc=;
tree[root].num=;
}else if (tree[root].l == tree[root].r){
tree[root].len=;
tree[root].lc=tree[root].rc=;
tree[root].num=;
}else{
tree[root].len=tree[L(root)].len+tree[R(root)].len;
tree[root].lc=tree[L(root)].lc;
tree[root].rc=tree[R(root)].rc;
tree[root].num=tree[L(root)].num+tree[R(root)].num-(tree[L(root)].rc && tree[R(root)].lc);
}
}
void buildtree(int root,int l,int r){
tree[root].l=l;
tree[root].r=r;
tree[root].s=tree[root].len=;
tree[root].lc = tree[root].rc = tree[root].num = ;
if (l==r){
return ;
}
int mid = MID(l,r);
buildtree(L(root),l,mid);
buildtree(R(root),mid+,r);
}
void update(int root,int ul,int ur,int v)
{
int l=tree[root].l;
int r=tree[root].r;
//cout<<root<<l<<" "<<r<<" "<<ul<<" "<<ur<<endl;
if (ul==l && ur==r)
{
tree[root].s+=v;
pushup(root);
return;
}
int mid = MID(l,r);
if (ur<=mid)update(L(root),ul,ur,v);
else if(ul>mid)update(R(root),ul,ur,v);
else{
update(L(root),ul,mid,v);
update(R(root),mid+,ur,v);
}
pushup(root);
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
int x1,x2,y1,y2,mx=-inf,mn=inf;
int tot=;
for (int i=;i<n;i++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
mx=max(mx,max(x1,x2));
mn=min(mn,min(x1,x2));
line[tot].l=x1;
line[tot].r=x2;
line[tot].h=y1;
line[tot++].f=;
line[tot].l=x1;
line[tot].r=x2;
line[tot].h=y2;
line[tot++].f=-;
}
sort(line,line+tot,cmp);
int ans=;
int last=;
buildtree(,mn,mx-);
// cout<<"ss"<<endl;
for (int i=;i<tot;i++)
{
// cout<<line[0].l<<" "<<line[0].r<<endl;
update(,line[i].l,line[i].r-,line[i].f);
ans+=abs(tree[].len-last);
ans+=(line[i+].h-line[i].h)**tree[].num;
last=tree[].len;
}
printf("%d\n",ans);
}
return ;
}
#include<iostream>#include<algorithm>#include<stdio.h>#include<string.h>usingnamespacestd; constint N = 5007; constint X = 20007; constint inf = 1<<29; inline int L(int r){return r<<1;}; inline int R(int r){return r<<1|1;}; inline int MID(int l,int r){return (l+r)>>1;}; struct Edge{ int l,r; int h; int f; }line[N*2]; struct node{ int l,r,len,s,num; //num这个区间有多少不连续的线段bool lc,rc;//区间左右端点是否被覆盖 }tree[X<<2]; bool cmp(Edge a,Edge b) { return a.h<b.h; } void pushup(int root) { if (tree[root].s){ tree[root].len=tree[root].r-tree[root].l+1;//没有离散化 tree[root].rc=tree[root].lc=1; tree[root].num=1; }elseif (tree[root].l == tree[root].r){ tree[root].len=0; tree[root].lc=tree[root].rc=0; tree[root].num=0; }else{ tree[root].len=tree[L(root)].len+tree[R(root)].len; tree[root].lc=tree[L(root)].lc; tree[root].rc=tree[R(root)].rc; tree[root].num=tree[L(root)].num+tree[R(root)].num-(tree[L(root)].rc && tree[R(root)].lc); } } void buildtree(int root,int l,int r){ tree[root].l=l; tree[root].r=r; tree[root].s=tree[root].len=0; tree[root].lc = tree[root].rc = tree[root].num = 0; if (l==r){ return ; } int mid = MID(l,r); buildtree(L(root),l,mid); buildtree(R(root),mid+1,r); } void update(int root,int ul,int ur,int v) { int l=tree[root].l; int r=tree[root].r; //cout<<root<<l<<" "<<r<<" "<<ul<<" "<<ur<<endl;if (ul==l && ur==r) { tree[root].s+=v; pushup(root); return; } int mid = MID(l,r); if (ur<=mid)update(L(root),ul,ur,v); elseif(ul>mid)update(R(root),ul,ur,v); else{ update(L(root),ul,mid,v); update(R(root),mid+1,ur,v); } pushup(root); } int main(){ int n; while(scanf("%d",&n)!=EOF){ int x1,x2,y1,y2,mx=-inf,mn=inf; int tot=0; for (int i=0;i<n;i++){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); mx=max(mx,max(x1,x2)); mn=min(mn,min(x1,x2)); line[tot].l=x1; line[tot].r=x2; line[tot].h=y1; line[tot++].f=1; line[tot].l=x1; line[tot].r=x2; line[tot].h=y2; line[tot++].f=-1; } sort(line,line+tot,cmp); int ans=0; int last=0; buildtree(1,mn,mx-1); // cout<<"ss"<<endl;for (int i=0;i<tot;i++) { // cout<<line[0].l<<" "<<line[0].r<<endl; update(1,line[i].l,line[i].r-1,line[i].f); ans+=abs(tree[1].len-last); ans+=(line[i+1].h-line[i].h)*2*tree[1].num; last=tree[1].len; } printf("%d\n",ans); } return0; }
POJ - 1177 线段树的更多相关文章
- Picture POJ - 1177 线段树+离散化+扫描线 求交叉图像周长
参考 https://www.cnblogs.com/null00/archive/2012/04/22/2464876.html #include <stdio.h> #include ...
- poj 2886 线段树+反素数
Who Gets the Most Candies? Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12744 Acc ...
- poj 3468(线段树)
http://poj.org/problem?id=3468 题意:给n个数字,从A1 …………An m次命令,Q是查询,查询a到b的区间和,c是更新,从a到b每个值都增加x.思路:这是一个很明显的线 ...
- POJ——3264线段树
题目: 输入两个数(m,n),m表示牛的头数,n表示查询的个数.查询时输入两个数(x,y),表示查询范围的起始值和终止值,查询结果是,这个区间内牛重量的最大值减去牛重量的最小值,数量级为1000,00 ...
- POJ 2828 线段树(想法)
Buy Tickets Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 15422 Accepted: 7684 Desc ...
- poj 2828 线段树
http://poj.org/problem?id=2828 学到的思维: 1.变化的或者后来的优先影响前面的,那么从最后一个往前看,最后一个就成了 确定的, 而且后来的也能够确定----假设从前往后 ...
- poj 2886 (线段树+反素数打表) Who Gets the Most Candies?
http://poj.org/problem?id=2886 一群孩子从编号1到n按顺时针的方向围成一个圆,每个孩子手中卡片上有一个数字,首先是编号为k的孩子出去,如果他手上的数字m是正数,那么从他左 ...
- poj 2828(线段树 逆向思考) 插队是不好的行为
http://poj.org/problem?id=2828 插队问题,n个人,下面n行每行a,b表示这个人插在第a个人的后面和这个人的编号为b,最后输出队伍的情况 涉及到节点的问题可以用到线段树,这 ...
- poj 2528(线段树+离散化) 市长的海报
http://poj.org/problem?id=2528 题目大意是市长竞选要贴海报,给出墙的长度和依次张贴的海报的长度区间(参考题目给的图),问最后你能看见的海报有几张 就是有的先贴的海报可能会 ...
随机推荐
- sql server 分组,取每组的前几行数据
sql中group by后,获取每组中的前N行数据,目前我知道的有2种方法 比如有个成绩表: 里面有字段学生ID,科目,成绩.我现在想取每个科目的头三名. 1. 子查询 select * from ...
- iOS开发创建UI的耗时操作处理
项目中有网络请求.读写操作等一系列耗时操作时,为了避免阻塞主线程,我们会把这些耗时操作放到子线程中去处理,当处理完成后,再回到主线程更新UI,这样就不会阻塞主线程.但是创建UI的时候一般都是在主线程中 ...
- Spring Cloud Config 配置属性覆盖优先级。
/** * Flag to indicate that the external properties should override system properties. * Default tru ...
- python数据类型分类以及运算类型
一.python数据类型 目录: 1.数字(整数.小数) 2.字符串(单引号.双引号.三引号) 3.元组 #元素确定之后不能修改 4.列表 #元素可以修改 5.集合 #不讲顺序,得到的结果没有重复元 ...
- 学习笔记---json和xml区别
测试web时经常和网页数据打交道,会遇到json格式和xml格式,整理整理,记录下来. json最常用的格式是键值对. {"firstName": "Brett" ...
- 数据挖掘---Matplotib的学习
什么是matplotlib mat - matrix 矩阵 二维数据 - 二维图表 plot - 画图 lib - libra ...
- 新近碰到的病毒(TR.Spy.Babonock.A)
先来段Microsoft的说明: Worm:Win32/Babonock.A Alert level: Severe Detected with Windows Defender Antivirus ...
- 【Teradata】磁盘碎片整理(ferret工具)
DEFRAGMENTcombines free sectors and moves them to the end of a cylinder.PACKDISKfill (or packs) cyli ...
- hTML 如何在不同页面上传递参数( 1 )
(1).一种是重定向跳转,超连<a>就是一种重定向跳转,这样的跳转request对象是传不到下一个页面的,下一个页面得到的request对象是一个新的对象,而不是上一个页面传过来的就得不到 ...
- JavaScript—Date对象详情
Date对象概述 javaScript 提供了 Date 类型来处理时间和日期.Date 对象内置一系列获取和设置日期时间信息的方法.(不是内置对象,需要自己new) javaScript 中的 Da ...