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 题目大意是市长竞选要贴海报,给出墙的长度和依次张贴的海报的长度区间(参考题目给的图),问最后你能看见的海报有几张 就是有的先贴的海报可能会 ...
随机推荐
- MyBatis笔记----报错:Exception in thread "main" org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)解决方法
报错 Exception in thread "main" org.apache.ibatis.binding.BindingException: Invalid bound st ...
- Redis高可用 Sentinel
官网: https://redis.io/topics/sentinel Redis的主从只能实现数据热备份的功能,主宕机后从无法自动接管服务,因此Redis推出了Sentinel的主从监控模式. S ...
- Django + Uwsgi + Nginx 实现生产环境部署
本节内容 uwsgi 介绍 uwsgi安装使用 nginx安装配置 django with nginx 如何在生产上部署Django? Django的部署可以有很多方式,采用nginx+uwsgi的方 ...
- Linux中环境变量中文件执行顺序
Linux 的变量可分为两类:环境变量和本地变量 环境变量:或者称为全局变量,存在于所有的shell 中,在你登陆系统的时候就已经有了相应的系统定义的环境变量了.Linux 的环境变量具有 ...
- cmd是命令提示符吗?
经常使用电脑的小伙伴对cmd有所了解,它能帮我们快速解决问题.搜索框中输入“cmd”,就可以看到命令提示符程序了.那么,命令提示符程序和cmd到底有着什么样的联系呢?下面就为大家讲解一下. CMD是c ...
- Visio画图--我的形状
本人用的Visio 2013 打开Visio后新建一个拓扑图,发现左侧形状一栏不见了 形状栏可以保存很多自定义图形,怎么才能将形状一栏重新显示出来呢?方法其实很简单,方法如下所示: 这时候我们就会发现 ...
- 《Java大学教程》—第21章 高级案例研究
21.3 需求:P510用例模型(use case model):用例图(use case diagram).用例(use case).行为说明(behaviour specification) ...
- Python requests上传文件demo
#!/usr/bin/env python # -*- coding: utf-8 -*- import requests headers = {'uuid': '5cb572b7-c0a7-4d90 ...
- json_encode里面经常用到的 JSON_UNESCAPED_UNICODE和JSON_UNESCAPED_SLASHES
php格式化json的函数json_encode($value,$options) 其中有2个比较常用到的参数 JSON_UNESCAPED_UNICODE(中文不转为unicode ,对应的数字 2 ...
- 微信硬件平台(九) 自己的服务器从微信获取token并保存txt
1安装crontab: yum install crontabs 说明: service crond start //启动服务 service crond stop //关闭服务 service cr ...