[HDOJ1828]Picture(扫描线,线段树,矩形并周长)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828

题意:求矩形并的周长。

很好发现一个规律,那就是扫描到当前状态,update之后的线段树中线段的长度减去update之前的长度差的绝对值恰好是当前段并后的水平或者垂直的线段长度。

那么。。存两棵线段树,横着扫一遍竖着扫一遍,加起来就行了。。

竟然没MLE。。。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3
  4 #define lrt rt << 1
  5 #define rrt rt << 1 | 1
  6 const int maxn = 5500;
  7 typedef struct Event {
  8     double l, r, hx;
  9     int sign;
 10 }Event;
 11 typedef struct Seg {
 12     double len;
 13     int sign;
 14 }Seg;
 15
 16 vector<Event> event1, event2;
 17 double hx[maxn<<1], hy[maxn<<1];
 18 Seg seg[maxn<<2];
 19 int hxcnt, hycnt;
 20 int n;
 21
 22 bool cmp(Event a, Event b) {
 23     if(a.hx != b.hx) return a.hx < b.hx;
 24     return a.sign > b.sign;
 25 }
 26
 27 int xid(double x) {
 28     return lower_bound(hx, hx+hxcnt, x) - hx + 1;
 29 }
 30
 31 int yid(double y) {
 32     return lower_bound(hy, hy+hycnt, y) - hy + 1;
 33 }
 34
 35 void build(int l, int r, int rt) {
 36     seg[rt].len = .0; seg[rt].sign = 0;
 37     if(l == r) return;
 38     int mid = (l + r) >> 1;
 39     build(l, mid, lrt);
 40     build(mid+1, r, rrt);
 41 }
 42
 43 void pushup(int l, int r, int rt) {
 44     if(seg[rt].sign) seg[rt].len = hx[r] - hx[l-1];
 45     else {
 46         if(l == r) seg[rt].len = .0;
 47         else seg[rt].len = seg[lrt].len + seg[rrt].len;
 48     }
 49 }
 50
 51 void pushup1(int l, int r, int rt) {
 52     if(seg[rt].sign) seg[rt].len = hy[r] - hy[l-1];
 53     else {
 54         if(l == r) seg[rt].len = .0;
 55         else seg[rt].len = seg[lrt].len + seg[rrt].len;
 56     }
 57 }
 58
 59 void update(bool flag, int L, int R, int sign, int l, int r, int rt) {
 60     if(L <= l && r <= R) {
 61         seg[rt].sign += sign;
 62         if(!flag) pushup(l, r, rt);
 63         else pushup1(l, r, rt);
 64         return;
 65     }
 66     int mid = (l + r) >> 1;
 67     if(L <= mid) update(flag, L, R, sign, l, mid, lrt);
 68     if(mid < R) update(flag, L, R, sign, mid+1, r, rrt);
 69     if(!flag) pushup(l, r, rt);
 70     else pushup1(l, r, rt);
 71 }
 72
 73 int main() {
 74     // freopen("in", "r", stdin);
 75     int _ = 1;
 76     double ax, ay, bx, by;
 77     while(~scanf("%d",&n)) {
 78         hxcnt = 0; event1.clear(); event2.clear();
 79         for(int i = 0; i < n; i++) {
 80             scanf("%lf%lf%lf%lf",&ax,&ay,&bx,&by);
 81             event1.push_back({ax, bx, ay, 1});
 82             event1.push_back({ax, bx, by, -1});
 83             event2.push_back({ay, by, ax, 1});
 84             event2.push_back({ay, by, bx, -1});
 85             hx[hxcnt++] = ax; hx[hxcnt++] = bx;
 86             hy[hycnt++] = ay; hy[hycnt++] = by;
 87         }
 88         sort(event1.begin(), event1.end(), cmp);
 89         sort(event2.begin(), event2.end(), cmp);
 90         sort(hx, hx+hxcnt); hxcnt = unique(hx, hx+hxcnt) - hx;
 91         sort(hy, hy+hycnt); hycnt = unique(hy, hy+hycnt) - hy;
 92         build(1, hxcnt, 1);
 93         double ret = .0;
 94         double pre = .0;
 95         for(int i = 0; i < event1.size(); i++) {
 96             int l = xid(event1[i].l);
 97             int r = xid(event1[i].r) - 1;
 98             int sign = event1[i].sign;
 99             update(0, l, r, sign, 1, hxcnt, 1);
100             ret += abs(seg[1].len - pre);
101             pre = seg[1].len;
102         }
103         event1.clear();
104         build(1, hycnt, 1);
105         pre = .0;
106         for(int i = 0; i < event2.size(); i++) {
107             int l = yid(event2[i].l);
108             int r = yid(event2[i].r) - 1;
109             int sign = event2[i].sign;
110             update(1, l, r, sign, 1, hycnt, 1);
111             ret += abs(seg[1].len - pre);
112             pre = seg[1].len;
113         }
114         cout << ret << endl;
115     }
116     return 0;
117 }
时间: 2024-08-26 12:38:33

[HDOJ1828]Picture(扫描线,线段树,矩形并周长)的相关文章

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,

[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

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

poj 1151 Atlantis (离散化 + 扫描线 + 线段树)

题目链接题意:给定n个矩形,求面积并,分别给矩形左上角的坐标和右上角的坐标. 分析: 1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <cstdlib> 6 #include <algorithm> 7 #define LL __int64 8 #define lson l, mid, 2*rt

HDU3265_Posters(扫描线/线段树)

解题报告 题意: 给定的矩形里面有镂空的矩阵,求矩阵面积并. 思路: 直接把一个图形拆成4个矩形,进行面积并. 扫描线+线段树 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #define LL __int64 using namespace std; struct Seg { int lx,rx,h,v; friend bool operator

HDU1377_Counting Squares(扫描线/线段树)

解题报告 题意: 矩形面积并. 思路: 扫描线+线段树 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Seg { int lx,rx,h,v; friend bool operator < (Seg a,Seg b) { return a.h<b.h; } } seg[500000]

HDU1542_Atlantis(扫描线/线段树+离散)

解题报告 题目传送门 题意: 求矩形并面积. 思路: 离散+线段树+扫描线. #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Seg { int v; double h,lx,rx; friend bool operator < (Seg a,Seg b) { return a.h<b

HNU12884_Area Coverage(扫描线/线段树+离散化)

解题报告 题目传送门 题意: 又是求面积并 思路: 又是求面积并,还被坑了,题目明明描述的是int坐标,用了double才过... #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; struct Seg { double lx,rx,h; int v; friend bool operator <(Seg