poj 1177 Picture
http://poj.org/problem?id=1177
经典线段树,求矩形并的周长。把坐标排个序,然后插入线段树,求其变化的和就可以了。轻松1y~
View Code
1 #include <cstdio> 2 #include <algorithm> 3 #include <vector> 4 5 using namespace std; 6 7 #define lson l, m, rt << 1 8 #define rson m + 1, r, rt << 1 | 1 9 #define root -10001, 10001, 1 10 11 const int maxn = 40005; 12 struct segTree{ 13 int sum[maxn << 2], low[maxn << 2], high[maxn << 2], late[maxn << 2]; 14 15 void up(int rt) { 16 int ls = rt << 1, rs = rt << 1 | 1; 17 18 sum[rt] = sum[ls] + sum[rs]; 19 low[rt] = min(low[ls], low[rs]); 20 high[rt] = max(high[ls], high[rs]); 21 } 22 void down(int rt) { 23 if (late[rt]) { 24 int ls = rt << 1, rs = rt << 1 | 1; 25 26 late[ls] += late[rt]; 27 late[rs] += late[rt]; 28 low[ls] += late[rt]; 29 low[rs] += late[rt]; 30 high[ls] += late[rt]; 31 high[rs] += late[rt]; 32 late[rt] = 0; 33 } 34 } 35 void build(int l, int r, int rt) { 36 sum[rt] = low[rt] = high[rt] = late[rt] = 0; 37 if (l == r) { 38 return ; 39 } 40 int m = (l + r) >> 1; 41 build(lson); 42 build(rson); 43 } 44 void fix(int l, int r, int rt) { 45 if (l == r || !high[rt] || low[rt]) { 46 if (low[rt]) { 47 sum[rt] = r - l + 1; 48 } else if (!high[rt]) { 49 sum[rt] = 0; 50 } 51 return ; 52 } 53 int m = (l + r) >> 1; 54 down(rt); 55 fix(lson); 56 fix(rson); 57 up(rt); 58 } 59 void update(int L, int R, int d, int l, int r, int rt) { 60 if (L <= l && r <= R) { 61 low[rt] += d; 62 high[rt] += d; 63 late[rt] += d; 64 if (low[rt]) { 65 sum[rt] = r - l + 1; 66 } else if (!high[rt]) { 67 sum[rt] = 0; 68 } else { 69 fix(l, r, rt); 70 } 71 return ; 72 } 73 int m = (l + r) >> 1; 74 down(rt); 75 if (L <= m) update(L, R, d, lson); 76 if (m < R) update(L, R, d, rson); 77 up(rt); 78 } 79 int query() { 80 fix(root); 81 return sum[1]; 82 } 83 } segT; 84 85 struct Rect { 86 int x1, y1; 87 int x2, y2; 88 } ; 89 vector<Rect> rect; 90 91 void input(int n) { 92 Rect buf; 93 94 rect.clear(); 95 while (n--) { 96 scanf("%d%d%d%d", &buf.x1, &buf.y1, &buf.x2, &buf.y2); 97 if (buf.x1 > buf.x2) swap(buf.x1, buf.x2); 98 if (buf.y1 > buf.y2) swap(buf.y1, buf.y2); 99 rect.push_back(buf); 100 swap(buf.x1, buf.x2); 101 swap(buf.y1, buf.y2); 102 rect.push_back(buf); 103 } 104 } 105 106 bool cmpx(Rect a, Rect b) { 107 return a.x1 < b.x1; 108 } 109 110 bool cmpy(Rect a, Rect b) { 111 return a.y1 < b.y1; 112 } 113 114 int deal() { 115 int last = 0, ret = 0; 116 vector<Rect>::iterator ii; 117 // cal x 118 sort(rect.begin(), rect.end(), cmpx); 119 segT.build(root); 120 for (ii = rect.begin(); ii != rect.end(); ii++) { 121 int y1 = (*ii).y1, y2 = (*ii).y2; 122 if (y1 < y2) { 123 segT.update(y1, y2 - 1, 1, root); 124 ret += segT.query() - last; 125 } else { 126 segT.update(y2, y1 - 1, -1, root); 127 ret += last - segT.query(); 128 } 129 last = segT.query(); 130 // printf("y %d %d %d\n", last, y1, y2); 131 } 132 // cal y 133 last = 0; 134 sort(rect.begin(), rect.end(), cmpy); 135 segT.build(root); 136 for (ii = rect.begin(); ii != rect.end(); ii++) { 137 int x1 = (*ii).x1, x2 = (*ii).x2; 138 if (x1 < x2) { 139 segT.update(x1, x2 - 1, 1, root); 140 ret += segT.query() - last; 141 } else { 142 segT.update(x2, x1 - 1, -1, root); 143 ret += last - segT.query(); 144 } 145 last = segT.query(); 146 // printf("x %d %d %d\n", last, x1, x2); 147 } 148 149 return ret; 150 } 151 152 int main() { 153 int n; 154 155 // freopen("in", "r", stdin); 156 while (~scanf("%d", &n)) { 157 input(n); 158 printf("%d\n", deal()); 159 } 160 161 return 0; 162 }
UPD:
之前没看懂这道题的正确做法,然后被我yy了一个只是用线段树优化的代码,并没有起到线段树的真正作用。现在补上最新的,用线段树完美维护的代码,16ms通过。
View Code
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 6 using namespace std; 7 8 #define _clr(x) memset(x, 0, sizeof(x)) 9 #define REP(i, n) for (int i = 0; i < (n); i++) 10 #define REP_1(i, n) for (int i = 1; i <= (n); i++) 11 12 struct Side { 13 int x1, x2, y, d; 14 Side() {} 15 Side(int _x1, int _x2, int _y, int _d) : x1(_x1), x2(_x2), y(_y), d(_d) {} 16 } x[11111], y[11111]; 17 18 bool cmp(Side a, Side b) { 19 if (a.y != b.y) return a.y < b.y; 20 return a.d > b.d; 21 } 22 23 void input(int n) { 24 int x1, y1, x2, y2; 25 REP(i, n) { 26 scanf("%d%d%d%d", &x1, &y1, &x2, &y2); 27 if (x1 > x2) swap(x1, x2); 28 if (y1 > y2) swap(y1, y2); 29 x[i << 1] = Side(x1, x2 - 1, y1, 1); 30 x[i << 1 | 1] = Side(x1, x2 - 1, y2, -1); 31 y[i << 1] = Side(y1, y2 - 1, x1, 1); 32 y[i << 1 | 1] = Side(y1, y2 - 1, x2, -1); 33 } 34 sort(x, x + (n << 1), cmp); 35 sort(y, y + (n << 1), cmp); 36 } 37 38 const int N = 22222; 39 int sum[N << 2], cnt[N << 2]; 40 41 #define lson l, m, rt << 1 42 #define rson m + 1, r, rt << 1 | 1 43 #define ROOT -10010, 10010, 1 44 45 void up(int rt, int len) { 46 if (cnt[rt]) { 47 sum[rt] = len; 48 } else { 49 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; 50 } 51 } 52 53 void build(int l, int r, int rt) { 54 sum[rt] = cnt[rt] = 0; 55 if (l == r) return ; 56 int m = (l + r) >> 1; 57 build(lson); 58 build(rson); 59 } 60 61 void update(int L, int R, int d, int l, int r, int rt) { 62 if (L <= l && r <= R) { 63 cnt[rt] += d; 64 up(rt, r - l + 1); 65 return ; 66 } 67 int m = (l + r) >> 1; 68 if (L <= m) update(L, R, d, lson); 69 if (m < R) update(L, R, d, rson); 70 up(rt, r - l + 1); 71 } 72 73 int sweepLine(Side *s, int n) { 74 n <<= 1; 75 int ret = 0, cur = 0; 76 build(ROOT); 77 REP(i, n) { 78 update(s[i].x1, s[i].x2, s[i].d, ROOT); 79 ret += abs(cur - sum[1]); 80 cur = sum[1]; 81 } 82 return ret; 83 } 84 85 int main() { 86 // freopen("in", "r", stdin); 87 int n; 88 while (~scanf("%d", &n)) { 89 input(n); 90 printf("%d\n", sweepLine(x, n) + sweepLine(y, n)); 91 } 92 return 0; 93 }
这个代码里面,就算是成段操作,也不用将结果推倒儿子节点处。这样一来就可以实现返回历史历史状态的效果了。
——written by Lyon