题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255
题目:可以参考hdu1542 http://blog.csdn.net/qq_36782366/article/details/75209119
思路:用sum数组记录重叠两次以上的边的长度 once数组记录重叠一次边的记录 方便于信息的向上传递
其他的与hdu1542一致,这里主要讲下这两个数组的使用
关于pushup函数的解释(重点)
void PushUp(int rt,int l,int r) {
if (cnt[rt]>=2)
{
sum[rt] = X[r+1] - X[l];//需要理解
once[rt]=0;
return;
}
if(cnt[rt]==1)
{
sum[rt] = once[rt<<1]+once[rt<<1|1]+sum[rt<<1]+sum[rt<<1|1];
once[rt]=X[r+1] - X[l]-sum[rt];
return ;
}
if(cnt[rt]==0)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
once[rt]=once[rt<<1]+once[rt<<1|1];
return ;
}
}
如果cntr【rt】等于2时,说明该区间被该区间长度的边覆盖了两层,所以对于sum(两层以上的的长度)就是该区间的长度,因为已经覆盖两层了,所以once长度即为0
如果cnt【rt】等于1时,说明该区间被该区间长度的边覆盖了一层,所以对于sum(两层以上的的长度)就是其子区间中覆盖一层和两层以上的长度和,对于once一层的长度为总的该区间长度减去两层以上的长度
如果cnt【rt】等于0时,说明该区间没有被该区间长度的边覆盖,所以对于sum(两层以上的的长度)就是其子区间中覆盖两层以上的长度和,对于once一层的长度即等于其子区间中覆盖一层的长度和
好了接下来直接上AC的代码
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int maxn = 22022;
int cnt[maxn << 2];
double sum[maxn << 2];
double once[maxn<<2];
double X[maxn];
struct Seg
{
double h , l , r;
int s;
Seg(){}
Seg(double a,double b,double c,int d) : l(a) , r(b) , h(c) , s(d) {}
bool operator < (const Seg &cmp) const
{
if( h==cmp.h)return s>cmp.s;
return h < cmp.h;
}
}ss[maxn];
void PushUp(int rt,int l,int r) {
if (cnt[rt]>=2)
{
sum[rt] = X[r+1] - X[l];//需要理解
once[rt]=0;
return;
}
if(cnt[rt]==1)
{
sum[rt] = once[rt<<1]+once[rt<<1|1]+sum[rt<<1]+sum[rt<<1|1];
once[rt]=X[r+1] - X[l]-sum[rt];
return ;
}
if(cnt[rt]==0)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
once[rt]=once[rt<<1]+once[rt<<1|1];
return ;
}
}
void update(int L,int R,int c,int l,int r,int rt)
{
if (L <= l && r <= R)
{
cnt[rt] += c;//这个位置的边的条数 如果大于0时需要计入底边
PushUp(rt , l , r);
return ;
}
int m = (l + r) >> 1;
if (L <= m)
update(L , R , c , lson);
if (m < R)
update(L , R , c , rson);
PushUp(rt , l , r);
}
int main()
{
int n , cas;
scanf("%d",&cas);
while (cas--)
{
scanf("%d",&n) ;
int m = 0;
while (n --)
{
double a , b , c , d;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
X[m] = a;
ss[m++] = Seg(a , c , b , 1);
X[m] = c;
ss[m++] = Seg(a , c , d , -1);
}
sort(X , X + m);
sort(ss , ss + m);
int k=unique(X,X+m)-X;
memset(cnt , 0 , sizeof(cnt));
memset(sum , 0 , sizeof(sum));
memset(once, 0 , sizeof(once));
double ret = 0;
for (int i = 0 ; i < m - 1 ; i ++)
{
int l=lower_bound(X,X+k,ss[i].l)-X;
int r =lower_bound(X,X+k,ss[i].r)-X-1;
if (l <= r) update(l , r , ss[i].s , 0 , k - 1, 1);//扫描线段时更新底边长度和底边相差个数
ret += sum[1] * (ss[i+1].h - ss[i].h);//底乘以高
}
printf("%.2lf\n", ret);
}
return 0;
}