poj1177
题意:在平面直角坐标系内给出一些与坐标轴平行的矩形,将这些矩形覆盖的区域求并集,然后问这个区域的周长是多少。(边与边重合的地方不计入周长)
分析:线段树。曾经做过类似的求矩形覆盖的总面积的题。这道题同样要使用扫描线算法。属于线保留型线段树。
我们先领扫描线与y轴平行。
线段树内每个节点除了要记录该区间被覆盖了几层之外,还要记录当前状态下扫描线在该区间(开区间)内与多少条与x轴平行的边相交。
节点上还有两个bool型变量,记录该区间内(包括子树)线段覆盖是否接触到该区间的起始和结束点。
在父节点如果没被整个覆盖,则需要从子区间的起始和结束点来更新父节点两端点的覆盖情况。
更新过程在返回时,父节点的交点数量应等于两子节点交点数量的和,另外特判一下两子区间的公共点(父节点的中点),判断这里是不是覆盖与未覆盖的分界点,如果是则还需要在父节点上增加这个交点。
这样就得知了每段与x轴平行的距离内有多少条线段需要计算,距离乘以数量即可。这样就计算出了所有与x轴平行的周长上的边的总长度。
之后让扫描线与x轴平行即可计算出与y轴平行的所有周长上的边的总长度。
#include <cstdio>
#include <algorithm>
using namespace std;
//scanning from left to right
//discretionize Ys
#define MAX_REC_NUM 5005
#define MAX_INTERVAL MAX_REC_NUM * 2 struct Node
{
int l, r;
Node *pleft, *pright;
int num;
bool to_left, to_right;
int edge_num;
}; int node_cnt;
Node tree[MAX_INTERVAL * ]; struct Interval
{
int start, end;
int pos;
int value;
Interval()
{}
Interval(int start, int end, int pos, int value):start(start), end(end), pos(pos), value(value)
{}
bool operator < (const Interval &a)const
{
if (pos != a.pos)
return pos < a.pos;
return value > a.value;
}
}interval[MAX_REC_NUM * ]; struct Rectangle
{
int l, d, u, r;
}rec[MAX_REC_NUM]; int discrete[MAX_REC_NUM * ];
int discrete_num;
int rec_num;
int interval_num; int get_index(int a)
{
return lower_bound(discrete, discrete + discrete_num, a) - discrete;
} void discretization(int discrete[], int &discrete_num)
{
sort(discrete, discrete + discrete_num);
discrete_num = unique(discrete, discrete + discrete_num) - discrete;
} void input()
{
scanf("%d", &rec_num);
for (int i = ; i < rec_num; i++)
{
int l, d, r, u;
scanf("%d%d%d%d", &l, &d, &r, &u);
rec[i].l = l;
rec[i].r = r;
rec[i].u = u;
rec[i].d = d;
}
} void make_xscan()
{
discrete_num = ;
interval_num = ;
for (int i = ; i < rec_num; i++)
{
int l, d, r, u;
l = rec[i].l;
r = rec[i].r;
u = rec[i].u;
d = rec[i].d;
interval[interval_num++] = Interval(d, u, l, );
interval[interval_num++] = Interval(d, u, r, -);
discrete[discrete_num++] = u;
discrete[discrete_num++] = d;
}
} void make_yscan()
{
discrete_num = ;
interval_num = ;
for (int i = ; i < rec_num; i++)
{
int l, d, r, u;
l = rec[i].l;
r = rec[i].r;
u = rec[i].u;
d = rec[i].d;
interval[interval_num++] = Interval(l, r, d, );
interval[interval_num++] = Interval(l, r, u, -);
discrete[discrete_num++] = l;
discrete[discrete_num++] = r;
}
} void buildtree(Node *proot, int s, int e)
{
proot->l = s;
proot->r = e;
proot->to_left = false;
proot->to_right = false;
proot->num = ;
proot->edge_num = ;
if (s == e)
{
proot->pleft = proot->pright = NULL;
return;
}
node_cnt++;
proot->pleft = tree + node_cnt;
node_cnt++;
proot->pright = tree + node_cnt;
buildtree(proot->pleft, s, (s + e) / );
buildtree(proot->pright, (s + e) / + , e);
} void recount(Node *p)
{
if (p->num > )
{
p->edge_num = ;
p->to_right = p->to_left = true;
return;
}
if (p->pleft == NULL || p->pright == NULL)
{
p->edge_num = ;
p->to_right = p->to_left = false;
return;
}
p->to_left = p->pleft->to_left;
p->to_right = p->pright->to_right;
p->edge_num = p->pleft->edge_num + p->pright->edge_num;
if (p->pleft->to_right != p->pright->to_left)
p->edge_num++;
} void insert(Node *proot, int s, int e, int value)
{
if (s > proot->r || e < proot->l)
return;
s = max(s, proot->l);
e = min(e, proot->r);
if (s == proot->l && e == proot->r)
{
proot->num += value;
recount(proot);
return;
}
insert(proot->pleft, s, e, value);
insert(proot->pright, s, e, value);
recount(proot);
} long long work()
{
long long ans = ;
for (int i = ; i < interval_num; i++)
{
int s = get_index(interval[i].start);
int e = get_index(interval[i].end) - ;
insert(tree, s, e, interval[i].value);
long long line_num = tree->edge_num;
if (tree->to_left)
line_num++;
if (tree->to_right)
line_num++;
if (i != interval_num - )
ans += (interval[i + ].pos - interval[i].pos) * line_num;
}
return ans;
} int main()
{
input();
long long ans = ;
make_xscan();
sort(interval, interval + interval_num);
discretization(discrete, discrete_num);
buildtree(tree, , discrete_num);
ans += work(); make_yscan();
sort(interval, interval + interval_num);
discretization(discrete, discrete_num);
buildtree(tree, , discrete_num);
ans += work(); printf("%lld\n", ans);
return ;
}
poj1177的更多相关文章
- 【poj1177】 Picture
http://poj.org/problem?id=1177 (题目链接) 题意 求矩形周长并. Solution 转自:http://www.cnblogs.com/Booble/archive/2 ...
- [POJ1177]Picture
[POJ1177]Picture 试题描述 A number of rectangular posters, photographs and other pictures of the same sh ...
- 【HDOJ1828&&POJ1177】Picture(线段树,扫描线)
题意:给定n个矩形,求他们的并的周长 n<=5e3,abs(x[i])<=1e4 思路:From https://www.cnblogs.com/kuangbin/archive/2013 ...
- POJ1177 Picture —— 求矩形并的周长 线段树 + 扫描线 + 离散化
题目链接:https://vjudge.net/problem/POJ-1177 A number of rectangular posters, photographs and other pict ...
- 扫描线矩形周长的并 POJ1177
//扫描线矩形周长的并 POJ1177 // 我是按x轴 #include <iostream> #include <cstdio> #include <cstdlib& ...
- POJ1177 Picture 线段树+离散化+扫描线
求最终的覆盖图形周长,写这种代码应该短而精确,差的比较远 /* Problem: 1177 User: 96655 Memory: 348K Time: 32MS Language: C++ Resu ...
- POJ1177+线段树+扫描线
思路: 以y的值进行离散化 根据x的值 对每一条y轴边进行处理,如果是"左边"则插入,是"右边"则删除. /* 扫描线+线段树+离散化 求多个矩形的周长 */ ...
- POJ-1177 Picture 矩形覆盖周长并
题目链接:http://poj.org/problem?id=1177 比矩形面积并麻烦点,需要更新竖边的条数(平行于x轴扫描)..求横边的时候,保存上一个结果,加上当前长度与上一个结果差的绝对值就行 ...
- IOI1998 hdu1828 poj1177 Picture
写了一发扫描线竟然狂WA不止,hdu死活过不了,poj和当时IOI的数据(还花了我1dsdn积分..)都过了. 然后看到谋篇blog里有评论,把数据拿下来发现WA了. 数据是 20 0 1 11 0 ...
随机推荐
- SpringMVC框架的工作原理
学习SpringMVC的工作原理,首先有三个要解决的问题: (1)DispathcherServlet框架如何截获特定的HTTP请求,交由SpringMVC处理? (2)位于Web层的Spring容器 ...
- Apache日志配置详解(rotatelogs LogFormat)
logs/error_logCustomLog logs/access_log common--默认为以上部分 修改为如下: ErrorLog "|/usr/sbin/rotatelogs ...
- IGV软件
它支持各种各样的数据类型,包括基于芯片测序.二代测序数据和基因组注释数据等.整合基因组浏览器(IGV,Integrative Genomics Viewer)进行可视化浏览,它支持各种各式的数据类型, ...
- No enclosing instance of type E is accessible. Must qualify the allocation with an enclosing
在Java中,类中的静态方法不能直接调用动态方法.只有将某个内部类修饰为静态类,然后才能够在静态类中调用该类的成员变量与成员方法.所以在不做其他变动的情况下,最简单的解决办法是将public clas ...
- redhat 下 rpm 指令
1.如何安装rpm软件包rmp软件包的安装可以使用程序rpm来完成.执行下面的命令 rpm -i your-package.rpm 其中your-package.rpm是你要安装的rpm包的文件名,一 ...
- 2.交通聚类 -层次聚类(agnes)Java实现
1.项目背景 在做交通路线分析的时候,客户需要找出车辆的行车规律,我们将车辆每天的行车路线当做一个数据样本,总共有365天或是更多,从这些数据中通过聚类来获得行车路线规律统计分析. 我首先想到是K-m ...
- debian8 配置使用 nfs
操作过的步骤: 1.dpkg-reconfigre rpcbind. 2.在终端上退出要挂载的目录. 错误:mount -t nfs 172.16.0.121:/home/junda /mnt,出现以 ...
- 汉字转拼音(pinyin4j)
1.引入依赖 <dependency> <groupId>pinyin4j.sourceforge.net</groupId> <artifactId> ...
- Docker 容器测试全探索
导读 当我们构建好Docker镜像并利用多套容器共同组合成应用程序,建立起持续交付通道,了解了如何将新创建的镜像纳入到生产或者测试环境当中之后,新的问题来了——我们该如何测试自己的Docker容器?测 ...
- Linux使用手册-vi使用手册
vi使用手册 VI是unix上最常用的文本编辑工具,作为unix软件测试人员,有必要熟练掌握它. 进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi +n filen ...