我是靠谱客的博主 帅气泥猴桃,最近开发中收集的这篇文章主要介绍扫描线求矩形周长HDU 1828Picture,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

先看大佬给的解释:

说完了矩形面积,矩形周长的方法自然是类似的,但是周长的计算却更复杂些,看这张图:

 

周长可以分成两部分计算,横线和竖线,如图将所有彩色的横线加起来就是横向的所有长度了

然后可以采用竖直方向的扫描线将竖线的所有长度求出来

那么怎么计算横线的长度呢?

横线的长度 = 【现在这次总区间被覆盖的程度和上一次总区间被覆盖的长度之差的绝对值】

想想为什么要加绝对值(提示:下边--删除,上边--插入)

这样用自下而上和从左往右的两次扫描即可得到答案。

但是,这样的方法显得有些笨,有没有更高端的方法呢?

再看一张图:

 

看出什么了吗?这张图在上面那张图的基础上多了几条竖线。

我的意思是说,我们可以只做一次自下而上的扫描就把横线竖线都算出来!

竖线的算法和上面说的方法一样:【现在这次总区间被覆盖的程度和上一次总区间被覆盖的长度之差的绝对值】

竖线要怎么计算?

首先我们现在改一下线段树保存的属性,我们用如下信息记录线段树的节点:

1. l , r : 该节点代表的线段的左右端点坐标

2.len : 这个区间被覆盖的长度(即计算时的有效长度)

3.s : 表示这个区间被覆盖了几次

4. lc , rc : 标记这个节点的左右两个端点是否被覆盖(0表示没有,1表示有)

5.num :这个区间有多少条线段(这个区间被多少条线段覆盖)

这里的num涉及到竖线的计算,故解释一下,举几个例子:

   若区间[0,10]被[1,2][4,5]覆盖,则num = 2

   若区间[0,10]被[1,3][4,5]覆盖,则num = 1(两区间刚好连在一起)

   若区间[0,10]被[1,5][2,6]覆盖,则num = 1(两区间连起来还是一段)

然后就可以计算竖线了:

竖线的长度 = 【下一条即将被扫到的横线的高度 - 现在扫到的横线的高度】*2*num

乘2是因为每条线段有两个端点;

看上图中棕色线段的竖线有4条,因为棕色的横线由2条线段组成

白色线段的竖线只有2条,因为白色的横线由1条线段组成(虽然这1条线段是由许多线段组合而成,但它依旧只算1条线段)

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h>
#include <stack>
const int maxn=1e5+7;
#define mod 998244353
#define Lson l,m,rt<<1
#define Rson m+1,r,rt<<1|1
typedef long long ll;
using namespace std;
int mi,mx;
int n;
struct Edeg
{
double l,r,h;
int flag;
Edeg()=default;
Edeg(double a,double b,double c,int d):l(a),r(b),h(c),flag(d){}
bool operator < (const Edeg &a) const
{
return h<a.h;
}
}edge[maxn*3];
struct Tree
{
int l,r;
double len;
int lazy;
bool lc,rc;
int num;
}tree[maxn<<2];
void Build(int l,int r,int rt)
{
tree[rt].l=l,tree[rt].r=r;
tree[rt].lazy=tree[rt].lc=tree[rt].rc=0;
tree[rt].num=tree[rt].len=0;
if(l==r) return;
int m=(l+r)>>1;
Build(Lson);
Build(Rson);
}
void push_up(int rt)
{
if(tree[rt].lazy)
{
tree[rt].len=tree[rt].r-tree[rt].l+1;
tree[rt].lc=tree[rt].rc=1;
tree[rt].num=1;
}
else if(tree[rt].l==tree[rt].r)
{
tree[rt].len=tree[rt].num=0;
tree[rt].lc=tree[rt].rc=0;
}
else
{
tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len;
tree[rt].lc=tree[rt<<1].lc,tree[rt].rc=tree[rt<<1|1].rc;
tree[rt].num=tree[rt<<1].num+tree[rt<<1|1].num-(tree[rt<<1].rc&tree[rt<<1|1].lc);
}
}
void updata(int L,int R,int v,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
tree[rt].lazy+=v;
push_up(rt);
return;
}
int m=(l+r)>>1;
if(L<=m) updata(L,R,v,Lson);
if(R>m)
updata(L,R,v,Rson);
push_up(rt);
}
int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
double x1,y1,x2,y2;
while(scanf("%d",&n)!=EOF)
{
mi=maxn,mx=-maxn;
for(int i=0;i<n;i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
edge[i*2]=Edeg(x1,x2,y1,1);
edge[i*2+1]=Edeg(x1,x2,y2,-1);
if(x1>mx) mx=x1;
if(x2>mx) mx=x2;
if(x1<mi) mi=x1;
if(x2<mi) mi=x2;
}
sort(edge,edge+2*n);
double ans=0;
double last=0;
Build(mi,mx-1,1);//有个0
for(int i=0;i<2*n;i++)
{
updata(edge[i].l,edge[i].r-1,edge[i].flag,mi,mx-1,1);
ans+=fabs(tree[1].len-last);
ans+=(edge[i+1].h-edge[i].h)*2*tree[1].num;
last=tree[1].len;
}
printf("%.0fn",ans);
}
return 0;
}

 

最后

以上就是帅气泥猴桃为你收集整理的扫描线求矩形周长HDU 1828Picture的全部内容,希望文章能够帮你解决扫描线求矩形周长HDU 1828Picture所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部