可以看看這裏: 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;
}