USACO5.5 矩形周长 Picture | 扫描线 + 线段树

题目:Luogu 1856

扫描线,将矩形拆成两条边分别为 +1 和 -1,计算无重叠部分的长度。

由于 update 区间 [a, b] 和 [b, c] 时会把 b 加两次,所以统一转换成 [a,b),累加长度的时候再将右端点右移。

需要注意,在覆盖一条边时,不能直接累加边的长度,像下图:

在覆盖边 [1,4] 前,[3,4] 已经累加过了,所以此时应该累计的是 [1,4] 的长度减去已经覆盖过的长度,然后再把 [1,4] 覆盖上;

相应的,在删除 [1,4] 这条边时,累计的是删除 [1,4] 前的长度 - 删除 [1,4] 后的长度。

其实就跟 矩形面积求并 这道题一样,线段树维护当前所有被覆盖的区间总长。

  1 #include <cstdio>
  2 #include <string>
  3 #include <cstring>
  4 #include <algorithm>
  5
  6 int read(); int abs(int);
  7
  8 struct Rectangle {
  9     int x1, x2, y1, y2;
 10 } rec[5005];
 11
 12 struct Line {
 13     int l, r, h, f;
 14     bool operator < (const Line &cmp) const {
 15         if (h == cmp.h) return f > cmp.f;
 16         return h < cmp.h;
 17     }
 18 } line[10005];
 19
 20 int hash[10005], cnt, sum[40005], tag[40005];
 21
 22 int find(int x, int l, int r) {
 23     while (l <= r) {
 24         int mid = l + ((r - l) >> 1);
 25         if (hash[mid] < x) l = mid + 1;
 26         else if (hash[mid] == x) return mid;
 27         else r = mid - 1;
 28     }
 29 }
 30
 31 void maintain(int cur, int l, int r) {
 32     if (tag[cur]) sum[cur] = hash[r + 1] - hash[l];
 33     else if (l == r) sum[cur] = 0;
 34     else sum[cur] = sum[cur << 1] + sum[cur << 1 | 1];
 35 }
 36
 37 void update(int cur, int l, int r, int L, int R, int flag) {
 38     if (L <= l && r <= R) tag[cur] += flag;
 39     else {
 40         int mid = l + ((r - l) >> 1);
 41         if (L <= mid) update(cur << 1, l, mid, L, R, flag);
 42         if (mid < R) update(cur << 1 | 1, mid + 1, r, L, R, flag);
 43     }
 44     maintain(cur, l, r);
 45 }
 46
 47 int solve() {
 48     int res = 0;
 49     std::sort(hash + 1, hash + cnt + 1);
 50     std::sort(line + 1, line + cnt + 1);
 51     for (int i = 1; i <= cnt; ++ i) {
 52         int l = find(line[i].l, 1, cnt),
 53             r = find(line[i].r, 1, cnt) - 1;
 54         if (l <= r) {
 55             int tmp = sum[1];
 56             update(1, 1, cnt, l, r, line[i].f);
 57             res += abs(sum[1] - tmp);
 58         }
 59     }
 60     return res;
 61 }
 62
 63 int main() {
 64     int n = read(), ans = 0;
 65     for (int i = 1; i <= n; ++ i) {
 66         rec[i].x1 = read(), rec[i].y1 = read(),
 67         rec[i].x2 = read(), rec[i].y2 = read();
 68         hash[++cnt] = rec[i].x1, line[cnt].l = rec[i].x1,
 69         line[cnt].r = rec[i].x2, line[cnt].h = rec[i].y1, line[cnt].f = 1;
 70         hash[++cnt] = rec[i].x2, line[cnt].l = rec[i].x1,
 71         line[cnt].r = rec[i].x2, line[cnt].h = rec[i].y2, line[cnt].f = -1;
 72     }
 73     ans += solve();
 74     cnt = 0;
 75     for (int i = 1; i <= n; ++ i) {
 76         hash[++cnt] = rec[i].y1, line[cnt].l = rec[i].y1,
 77         line[cnt].r = rec[i].y2, line[cnt].h = rec[i].x1, line[cnt].f = 1;
 78         hash[++cnt] = rec[i].y2, line[cnt].l = rec[i].y1,
 79         line[cnt].r = rec[i].y2, line[cnt].h = rec[i].x2, line[cnt].f = -1;
 80     }
 81     ans += solve();
 82     printf("%d\n", ans);
 83     return 0;
 84 }
 85
 86 int abs(int x) {
 87     if (x >= 0) return x; return -x;
 88 }
 89
 90 int read() {
 91     int x = 0, f = 1;
 92     char c = getchar();
 93     while (!isdigit(c)) {
 94         if (c == ‘-‘) f = -1;
 95         c = getchar();
 96     }
 97     while (isdigit(c)) {
 98         x = (x << 3) + (x << 1) + (c ^ 48);
 99         c = getchar();
100     }
101     return x * f;
102 }

再说说暴力的做法,个人感觉这个不是很科学,是可以被卡掉的。

暴力就是考虑到 +1 的时候只累计由 0 变成 1 的区间,-1 的时候只累计由 1 变成 0 的区间,O(n^2) 累加 ans。

原文地址:https://www.cnblogs.com/milky-w/p/8519398.html

时间: 2024-10-11 22:37:07

USACO5.5 矩形周长 Picture | 扫描线 + 线段树的相关文章

[USACO5.5]矩形周长Picture[扫描线+线段树]

题意:给出一些矩阵,求这些矩阵合并后外部(被包括在内部的不算)周长 端点-1这个是用点代替了边,区间内有几个点就代表区间长度是多少 #include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; inline void chmax(int &x, int y) {if (x < y) x = y;} inline void chmin(int &x, int y) {if (x >

luogu P1856 [USACO5.5]矩形周长Picture 扫描线 + 线段树

Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void setIO(string s) { string in=s+".in"; freopen(in.c_str(),"r",stdin); } struct Edge { int l,r,h,flag; }edges[maxn]; int n; namespace tr

[线段树扫描线][USACO5.5]矩形周长Picture

墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 所有矩形的边界.所有矩形顶点的坐标都是整数. 输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形.接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间). 输出文件只有一个正整数,表示所有矩形的周长. 题解 线段树扫描线  https://www.luogu.org/problemnew/sol

hdu1828 (Picture) &amp;poj 1177( Picture)&amp;sdibt 2390(5.5.1 Picture 矩形周长)(线段树+扫描)

题目地址:hdu1828 (Picture)  & poj 1177( Picture) & sdibt 2390(5.5.1 Picture 矩形周长) 题目大意: 给你N个矩形,求出N个矩形构成的周长. 解题思路: 线段数+扫描线. 推荐博客: POJ1177 Picture(线段树求轮廓周长) POJ 1177 Picture (线段树+离散化+扫描线) 详解 注意事项: 该题在求面积的基础上有了升级,多写了一个被调需要求出投影与Y轴有几段,不然样例会少算20,就是给出图形中间的小矩

POJ1151Atlantis 矩形面积并 扫描线 线段树

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ1151 题意概括 给出n个矩形,求他们的面积并. n<=100 题解 数据范围极小. 我们分3种算法逐步优化. 算法1: O(n3) 如果这n个矩形的坐标都是整数,而且比较小,那么我们显然可以用最暴力的方法:一个一个打标记. 但是不是这样的. 坐标大小很大,而且是实数. 然而我们发现差不多,只要先离散化一下,然后再打标记即可. 算法2:O(n2) 实际上,上面的方法十分慢.如果n的范围到了1000,

poj-1177 Picture(矩形周长并,线段树+扫描线)

题目链接:点击打开链接 Picture Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 11706   Accepted: 6175 Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical o

[USACO5.5] 矩形周长Picture

https://www.luogu.org/problemnew/show/P1856 1.每个矩形由两条横向边和两条纵向边组成. 2.对于横向边,按纵坐标排序.设当前讨论的边为 A [s , t] 如果 A 是某个矩形的靠下的边,在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x); 如果 A 是某个矩形的靠上的边,先删除它的对应边,再在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x); 3.对于纵向边,按横坐标排序,讨论方法与横向边相

hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积

题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> #include <algorithm> #define MAXN 110 #define LL ((rt<<1)+1) #define RR ((rt<<1)+2) using namespace std; int n; struct segment{ double l

POJ训练计划1177_Picture(扫描线/线段树+离散)

解题报告 题意: 求矩形周长和. 思路: 左扫上扫,扫过了. #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; struct Seg { int lx,rx,ly,ry,h,v; friend bool operator < (Seg a,Seg b) { re