POJ - 1177 Picture(线段树 扫描线 区间合并)
来源:互联网 发布:java马尔可夫链 编辑:程序博客网 时间:2024/05/19 02:19
题目大意:给你N个矩形,要求你求出这N个矩形的轮廓线周长
解题思路:先离散化坐标,接着进行扫描线,我是离散x坐标的
先讨论一下,和x轴平行的轮廓线的周长,这里分两种情况的线
1.添加一条下线,如果总长度有增加的话,那么多出来的长度是属于轮廓线的一部分的,如果总长度没有增加,表示这条线被包含在内了,不属于轮廓线
2.添加一条上线,如果总长度有减少的话,那么减少的部分是属于轮廓线的,如果没有减少,表示该线被包含在内了,不属于轮廓线,这个可以画图观察
接下来要求的是和y坐标平行的轮廓线的周长了,和y坐标平行的轮廓线的周长就是找出所给线段的y坐标所连成的不相交的线段,有多少个,就表示有多少条和y坐标平行的轮廓线,然后乘上高度*2即可。
所以我们维护区间内的不相交的线段的数量sum,区间的最左端点是否被包括left,区间的最右端点是否被包括right
接下来进行的就是区间合并了,如果当前区间被cover了,那么sum = left = right = 1
如果没被cover,且l == r , sum = left = right = 0
如果没被cover且l != r,那sum[u] = sum[u << 1] + sum[u << 1 | 1],还得要判断一下,区间能否连续,如果能连续,那么sum[u]–,判断连续的话,就用right[u << 1]和left[u << 1 | 1],如果两个都是1,那么就是连续的了,并起来
#include <cstdio>#include <cstring>#include <algorithm>#include <cstdlib>using namespace std;const int N = 10010 << 2;struct Segment{ int l, r, h, f;}S[N];int n, m, cnt;int pos[N], cover[N], len[N], left[N], right[N], sum[N];void build(int u, int l, int r) { len[u] = cover[u] = left[u] = right[u] = sum[u] = 0; if (l == r) return ; int mid = (l + r) >> 1; build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r);}int cmp(const Segment a, const Segment b) { return a.h < b.h;}void init() { int x1, y1, x2, y2; cnt = 1; for (int i = 1; i <= n; i++) { scanf("%d%d%d%d", &x1, &y1, &x2, &y2); pos[cnt] = S[cnt].l = S[cnt + 1].l = x1; pos[cnt + 1] = S[cnt].r = S[cnt + 1].r = x2; S[cnt].h = y1; S[cnt + 1].h = y2; S[cnt].f = 1; S[cnt + 1].f = -1; cnt += 2; } m = 1; sort(S + 1, S + cnt, cmp); sort(pos + 1, pos + cnt); for (int i = 2; i < cnt; i++) if (pos[i] != pos[i - 1]) pos[++m] = pos[i]; build(1, 1, m);}void getlen(int u, int l, int r) { if (cover[u]) { len[u] = pos[r + 1] - pos[l]; sum[u] = left[u] = right[u] = 1; } else if (l == r) len[u] = sum[u] = left[u] = right[u] = 0; else { len[u] = len[u << 1] + len[u << 1 | 1]; sum[u] = sum[u << 1] + sum[u << 1 | 1]; if (right[u << 1] && left[u << 1 | 1]) sum[u]--; left[u] = left[u << 1]; right[u] = right[u << 1 | 1]; }}void Modify(int u, int l, int r, int L, int R, int c) { if (l == L && r == R) { cover[u] += c; getlen(u, l, r); return ; } int mid = (l + r) >> 1; if (R <= mid) Modify(u << 1, l, mid, L, R, c); else if (L > mid) Modify(u << 1 | 1, mid + 1, r, L, R, c); else { Modify(u << 1, l, mid, L, mid, c); Modify(u << 1 | 1, mid + 1, r, mid + 1, R, c); } getlen(u, l, r);}int find(int val) { int l = 1, r = m; while (l <= r) { int mid = (l + r) >> 1; if (pos[mid] == val) return mid; else if (pos[mid] < val) l = mid + 1; else r = mid - 1; } return -1;}void solve() { int ans = 0, last = 0; for (int i = 1; i < cnt; i++) { int l = find(S[i].l); int r = find(S[i].r) - 1; Modify(1, 1, m, l, r, S[i].f); if (i < cnt - 1) { ans += sum[1] * (S[i + 1].h - S[i].h) * 2; ans += abs(len[1] - last); last = len[1]; } else ans += abs(len[1] - last); } printf("%d\n", ans);}int main() { while (scanf("%d", &n) != EOF) { init(); solve(); }}
0 0
- POJ - 1177 Picture(线段树 扫描线 区间合并)
- POJ 1177 Picture (线段树扫描线)
- HDU 1828 Picture (线段树扫描线求周长并 区间合并)
- poj 1177 Picture 线段树+离散化+线扫描
- POJ 1177 Picture (线段树+离散化+扫描线) 详解
- picture 1177 poj 线段树+扫描线+离散化
- poj - 1177 - Picture(离线化+扫描线+线段树)
- 【线段树+扫描线】 HDOJ 1828 && POJ 1177 Picture
- POJ 1177 Picture [离散化+扫描线+线段树]
- POJ 1177 Picture(线段树+扫描线)
- poj 1177 Picture 【线段树 扫描线 求轮廓周长】
- POJ 1177:Picture(线段树-扫描线)
- POJ 1177&&HDU1828 Picture 线段树+扫描线
- POJ 1177-Picture(线段树+离散化+扫描线)
- Picture - POJ 1177 扫描线 矩阵合并的周长
- POJ 2482 Stars in Your Window (线段树区间合并+扫描线)
- hdu 1828(poj 1177)Picture(线段树+扫描线)(轮廓线)
- poj 1177 Picture 线段树加扫描线
- Framengs杂记一
- vm 10 +centos6.3 安装
- 论MySQL何时使用索引,何时不使用索引
- IOS 代码块block :capturing self strongly in this block is 告警
- 在Eclipse中使用Axis2插件自动生成WSDL文件
- POJ - 1177 Picture(线段树 扫描线 区间合并)
- 如何优化 Java 性能?
- mysql 的 find_in_set函数使用方法
- Android开发中SQLite在多线程并发访问的应用
- 堆和栈的区别(转过无数次的文章)
- iOS开发心得记录1
- CSS中关于触发BFC
- 常用Linux命令收集
- 设计模式之外观模式