可以看看这里: http://www.cnblogs.com/Booble/archive/2010/10/10/1847163.html
为了写扫描线, 大概写了有史以来最丑的线段树了。
poj 1177 && hdu 1828 都是求矩形周长并,周长并改一改就可以求面积并了。
其实思想并不复杂,将x维排序,将x维上的2n条线段作为事件,每个事件统计与上个事件之间的所占周长长度。
统计周长长度有点烦, 在y维上要用线段树维护: 共有多长的线段被覆盖,以及共有多少“团”线段。
每次加的答案就是 : 覆盖值得改变量 + (当前线段与前一线段的距离) * 2 * (线段"团"数);
至于线段树,离散之后我维护了六个标记(貌似有神犇只要用三个标记+.+),而且合并的时候写的十分丑陋;
维护了这么六个值: 该区间覆盖最小值,最小值是否在左区间/右区间,最小值出现次数以及团数,以及为了维护最小值而保留的另一个标记。
反正就是很丑,写了5KB,难得有线段树写的这么丑。
# include <cstdio> # include <cstdlib> # include <cmath> # include <cstring> using namespace std; const int maxn = 7000; int len[maxn*2], old[maxn*2],left[maxn], right[maxn], low[maxn],high[maxn]; int newlow[maxn], newhigh[maxn], num[maxn*2], id[maxn*2]; int bj[maxn*4], tmin[maxn*4], tot[maxn*4], repeat[maxn*4]; bool covl[maxn*4], covr[maxn*4]; int top, mat, ans, h, st, n, i; void sort(int l, int r) { int i = l, j = r, d = num[(l + r) >> 1], dj = id[(l + r) >> 1] % 2,tmp; for (;i <= j;) { for (;(num[i] < d) || (num[i] == d && (id[i] % 2) < dj);i++); for (;(num[j] > d) || (num[j] == d && (id[j] % 2) > dj);j--); if (i <= j) tmp = num[i], num[i] = num[j], num[j] = tmp, tmp = id[i], id[i] = id[j], id[j] = tmp, i++, j--; } if (i < r) sort (i, r); if (l < j) sort (l, j); } void prepare_y() { int i; mat = 1, top = 0; for (i = 1; i <= n; i++) { num[++top] = low[i], id[top] = i * 2; num[++top] = high[i], id[top] = i * 2 +1; } sort(1, top); for (i = 1; i <= top; i++) { if (num[i] != num[i - 1]) mat++; if ((id[i] & 1) == 0 ) newlow[id[i] >> 1] = mat, old[mat] = low[id[i] >> 1]; else newhigh[id[i] >> 1] = mat, old[mat] = high[id[i] >> 1]; } for (h = 0, st = 1; st <= mat + 1; st <<= 1, h ++); for (i = 1; i <= st * 2; i++) len[i] = 1; for (i = 1; i <= mat-1; i++) len[st + i] = old[i+1] - old[i]; for (i = st-1; i>=1; i--) len[i] = len[i << 1]+ len[(i << 1)+1]; memset(id, 0, sizeof(id)); memset(num, 0, sizeof(num)); } void prepare_x() { top = 0; for (i = 1; i <= n; i++) { num[++top] = left[i], id[top] = i * 2; num[++top] = right[i], id[top] = i * 2 +1; } sort(1, top); } void origin() { memset(bj, 0, sizeof(bj)); memset(tmin, 0, sizeof(tmin)); memset(covl, true, sizeof(covl)); memset(covr, true, sizeof(covr)); for (int i = 1; i <= st * 2; i++) repeat[i] = 1, tot[i] = 1; for (int i = 1; i <= mat; i++) tot[i +st] = len[i+st]; for (int i = st - 1; i >= 1; i--) tot[i] = tot[i << 1] + tot[(i << 1 )+1]; } int min(int x, int y) { return x < y ? x: y; } void up(int x) { for (; x>= 1; x >>=1) { tmin[x] = min(tmin[x << 1], tmin[(x << 1) +1]); if (tmin[x << 1] == tmin[(x << 1) +1]) { repeat[x] = repeat[x << 1] + repeat[(x << 1) +1] - (covr[x << 1] && covl[(x << 1)+1]); tot[x] = tot[x << 1] + tot[(x << 1 )+1]; covl[x] = covl[x << 1], covr[x] = covr[(x << 1) +1]; } else if (tmin[x << 1] < tmin[(x << 1) +1]) { repeat[x] = repeat[x << 1]; tot[x] = tot[x << 1]; covl[x] = covl[x << 1], covr[x] = false; } else { repeat[x] = repeat[(x << 1)+1]; tot[x] = tot[(x << 1) +1]; covr[x] = covr[(x << 1)+1]; covl[x] = false; } } } void down(int x) { int i, now; for (i = h; i>0; i--) { now = x >> i; if (bj[now] != 0) { bj[now << 1]+= bj[now], bj[(now << 1) +1]+= bj[now]; tmin[now << 1]+= bj[now], tmin[(now << 1)+1]+= bj[now]; bj[now]= 0; } } } void change(int l, int r, int d) { l = l+st-1, r = r+st+1; int ll = l >> 1, rr = r >> 1; down(l); down(r); for (;(l ^ r) != 1; l >>= 1, r >>= 1) { if ((l & 1) == 0) bj[l+1]+=d, tmin[l+1]+=d; if ((r & 1) == 1) bj[r-1]+=d, tmin[r-1]+=d; } up(ll); up(rr); } void help() { for (int i = 1; i <= st; i++) down(i+st); } int main() { freopen("1177.in", "r", stdin); freopen("1177.out", "w", stdout); while (scanf("%d", &n) != EOF) { for (i = 1; i <= n; i++) scanf("%d%d%d%d", &left[i], &low[i], &right[i], &high[i]); prepare_y(); prepare_x(); origin(); ans = high[id[1] >> 1] - low[id[1] >> 1]; change(newlow[id[1] >> 1], newhigh[id[1] >> 1]-1, 1); for (i = 2; i <= top; i++) { //help(); int who = id[i] >> 1; int a1 = len[1]- tot[1] , a2 = repeat[1]; if ((who << 1)== id[i]) change(newlow[who], newhigh[who]-1, 1); else change(newlow[who], newhigh[who]-1, -1); int b1 = len[1]- tot[1] ; ans += abs(a1 - b1) + (num[i] - num[i-1]) * 2 * (a2 - 1); } printf("%d\n", ans); } return 0; }
ps: hdu上居然是多组数据,贡献了六七个wa。
附带一个poj1151 求矩形面积并的, 稍微好些一点;
# include <cstdlib> # include <cstdio> # include <cmath> # include <cstring> using namespace std; const int maxn = 200; int id[maxn]; double num[maxn], left[maxn], right[maxn], low[maxn], high[maxn], old[maxn*2], tot[maxn*4], len[maxn*4]; int tmin[maxn*4], bj[maxn*4], newlow[maxn], newhigh[maxn]; int test, h, st, n, top, mat; double ans; void sort(int l, int r) { double d = num[(l + r)>> 1], tmpd; int i = l, j = r, tmp, dj = id[(l + r)>> 1] & 1; for (;i <= j;) { for (;num[i] < d || (num[i] == d && (id[i] & 1) < dj); i++); for (;num[j] > d || (num[j] == d && (id[j] & 1) > dj); j--); if (i <= j) tmpd=num[i], num[i]=num[j], num[j]=tmpd, tmp=id[i], id[i]=id[j], id[j]=tmp, i++,j--; } if (i < r) sort(i, r); if (l < j) sort(l, j); } void prepare_y() { memset(num, 0, sizeof(num)); memset(id, 0, sizeof(id)); int i; top = 0; mat = 1; for (i = 1; i <= n; i++) { num[++top] = low[i]; id[top] = i * 2; num[++top] = high[i]; id[top] = i * 2 + 1; } sort(1, top); for (i = 1; i <= top; i++) { if (num[i] != num[i-1]) mat++; if ((id[i] & 1) == 0) newlow[id[i] >> 1] = mat, old[mat] = low[id[i] >> 1]; else newhigh[id[i] >> 1] = mat, old[mat] = high[id[i] >> 1]; } for (st = 1, h = 0; st <= mat +1; st <<= 1, h++); for (i = 1; i <= st*2; i++) len[i] = 1; for (i = 1; i <= mat-1; i++) len[i+st] = old[i+1] - old[i]; for (i = st-1; i >= 1; i--) len[i] = len[i << 1] + len[(i << 1)+1]; } void prepare_x() { memset(num, 0, sizeof(num)); memset(id, 0, sizeof(id)); int i; top = 0; mat = 1; for (i = 1; i <= n; i++) { num[++top] = left[i], id[top] = i * 2; num[++top] = right[i], id[top] = i * 2 +1; } sort(1, top); } void origin() { int i; ans = 0; memset(tmin, 0, sizeof(tmin)); memset(bj, 0 ,sizeof(bj)); for (i = 1; i <= st*2; i++) tot[i] = len[i]; } void read() { int i; scanf("%d", &n); for (i = 1; i <= n; i++) scanf("%lf%lf%lf%lf", &left[i], &low[i], &right[i], &high[i]); prepare_y(); prepare_x(); origin(); } void down(int x) { int i; for (i = h; i > 0; i--) { int now = x >> i; if (bj[now] != 0) { bj[now << 1]+= bj[now]; bj[(now << 1)+1]+= bj[now]; tmin[now << 1]+=bj[now]; tmin[(now << 1)+1]+= bj[now]; bj[now] = 0; } } } int min(int x, int y) { return x < y ? x:y ; } void up(int x) { for (;x > 0; x >>=1) { tmin[x] = min(tmin[x << 1], tmin[(x << 1)+1]); if (tmin[x << 1] == tmin[(x << 1)+1]) tot[x] = tot[x << 1] + tot[(x << 1)+1]; else if (tmin[x << 1] < tmin[(x << 1)+1]) tot[x] = tot[x << 1]; else tot[x] = tot[(x << 1)+1]; } } void change(int l, int r, int d) { l = l+st-1; r= r+st+1; int ll = l >> 1, rr = r >> 1; down(l); down(r); for (;(l ^ r) != 1; l>>=1, r>>=1) { if ((l & 1) == 0) tmin[l+1]+= d, bj[l+1]+= d; if ((r & 1) == 1) tmin[r-1]+= d, bj[r-1]+= d; } up(ll); up(rr); } int i; int main() { freopen("1151.in", "r", stdin); freopen("1151.out", "w", stdout); for (test = 1;;test++) { read(); if ( n == 0) break; change(newlow[id[1] >> 1], newhigh[(id[1]>>1)]-1, 1); for (i = 2; i <= top; i++) { ans += (num[i] - num[i-1]) * (len[1] - tot[1]); if ((id[i] & 1) == 0) change(newlow[id[i] >> 1], newhigh[(id[i]>>1)]-1, 1); else change(newlow[id[i] >> 1], newhigh[(id[i]>>1)]-1, -1); } printf("Test case #%d\n", test); printf("Total explored area: %.2lf\n\n", ans); } return 0; }