比较经典的一道题,线段树 + 扫描线,今年第一次看到这道题懵懵懂懂感觉以前做过,不过找不到代码了记得以前也是一知半解现在看也不会索性又研究了一下,现在再看这个东西感觉有点想法了,不过对于细节还是不知道该怎么处理。最后看了题解ac,不过这次是真的懂了以后也不怕了。
题意大致是给了几个相互重叠的矩形然后让你求出其面积。
将每个矩形的上下两条水平边存到数组中(得记录这条边是下边还是上边,为了计算覆盖次数,下边记为1,上边记为-1),按y的大小排序;从y最小的边开始向上扫描,首先将一条边插入线段树,然后得到当前当前扫描线所在位置的覆盖到的边的总长,
第一次是A1B1边插入到书中,扫描线覆盖到的边的总长就是A1B1,再拿他乘以当前高度和下一条边的高度差,得到底下那个矩形的面积
第二次是第二条黑边插入线段树,这时扫描到的总长度为A2B2,再拿他乘以当前高度和下一条边的高度差,得到中间那个长矩形的面积
第三次是A1B1的对边插入线段树,因为这条边是上边,所以覆盖次数会被-1,挺次,原先线段树中被A1B1覆盖的部分会被-1,所以,此时线段树中能够计算得到扫面线扫到的总长为A3B3的长度,再拿他乘以当前高度和下一条边的高度差,得到最上面那个矩形的面积
三者相加就是总面积了
另外这道题还需要注意的就是在递归update的时候和其他的线段树略有区别,因为是每对L ,R记录下一段区间而不是L,R 各表示一个点所以底层节点应该是R - L== 1 而不是R == L;而且递归时也应该是:
int mid = (L + R) >> 1;
if(ql < mid) update(o << 1,L,mid);
if(qr > mid) update(o << 1 | 1,mid,R);
好了废话不多说了,这道题还需要不断温习希望自己不要再忘了,以后也不要再怕线段树了!!加油beyhhhh!!
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <functional>
#include <cstdio>
#include <queue>
#include <map>
#include <algorithm>
#include <stack>
#include <utility>
typedef long long ll;
using namespace std;
const int mx = 210;
struct line
{
double r,l,h;
int f;
line() {}
line(double a,double b,double c,int d):l(a),r(b),h(c),f(d) {}
} a[mx << 2];
double sum[mx << 2],xl[mx];
int cov[mx << 2];
map <double,int> m;
int ql,qr,co;
int cmp(const line &a,const line &b)
{
return a.h < b.h;
}
void update(int o,int L,int R)
{
// printf("o = %d L = %d R = %d sum = %.2lf cov = %d\n",o,L,R,sum[o],cov[o]);
if(ql <= L&&R <= qr)
{
cov[o] += co;
if(cov[o])
sum[o] = xl[R] - xl[L];
else
{
if(R - L == 1) sum[o]= 0;
else sum[o] = sum[o << 1] + sum [o << 1 | 1];
}
// printf("o = %d L = %d R = %d sum = %.2lf cov = %d\n",o,L,R,sum[o],cov[o]);
return;
}
int mid = (L + R) >> 1;
if(ql < mid) update(o << 1,L,mid);
if(qr > mid) update(o << 1 | 1,mid,R);
if(cov[o])
sum[o] = xl[R] - xl[L];
else
{
if(R - L == 1) sum[o]= 0;
else sum[o] = sum[o << 1] + sum [o << 1 | 1];
}
// printf("o = %d L = %d R = %d sum = %.2lf cov = %d\n",o,L,R,sum[o],cov[o]);
}
int main ()
{
int n,i,l,r,k,j;
double x1,x2,y1,y2,ans;
int cas = 0;
int cnt,flage;
while (scanf("%d",&n)&&n)
{
cnt = 0;
flage = 0;
for(i = 0; i < n; i++)
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
a[cnt++] = line(x1,x2,y1,1);
a[cnt++] = line(x1,x2,y2,-1);
if(m[x1] == 0) m[x1] = ++flage;
if(m[x2] == 0) m[x2] = ++flage;
}
map<double,int>::iterator iter;
k = 0;
for(iter = m.begin(); iter != m.end(); iter++)
{
xl[++k] = iter -> first;
iter -> second = k;
// printf("xl = %.f k = %d\n",xl[k],k);
}
sort(a,a+cnt,cmp);
memset(sum,0,sizeof(sum));
memset(cov,0,sizeof(cov));
ans = 0;
// printf("cov = %d\n",cov[1]);
for(i = 0; i < cnt - 1; i++)
{
qr = m[a[i].r];
ql = m[a[i].l];
co = a[i].f;
// printf("co = %d\n",co);
update(1,1,k);
// printf(" a[i + 1].h = %.f a[i].h = %.f sum = %.f\n",a[i+1].h,a[i].h,sum[1]);
ans += (a[i+1].h - a[i].h) * sum[1];
}
printf("Test case #%d\n",++cas);
printf("Total explored area: %.2f\n\n",ans);
m.clear();
}
}