题目链接:Problem - 1255
分析:
此题实际上就是在基础扫描线的基础上加了一个条件,覆盖两次及以上的总面积。
基础扫描线题目:线段树 + 扫描线 + 离散化:亚特兰蒂斯_啦啦啦32421的博客-CSDN博客
此题就是在这道题目的基础上求至少覆盖两次的总面积。
实际上此题就是在模板题的基础上,在线段树上,既维护原先的len,作为新的len1也就是至少覆盖一次的总的y的长度。
在加一个维护的条件,len2,至少覆盖两次的总的y的长度。这个就是我们新的要用的高。
那么len2需要怎么进行维护呢?也就是pushup()怎么进行计算呢?
1.当这个区间的cnt >= 2的时候, 直接求这个区间的长度就可以了。
2.当这个区间的cnt == 1的时候,也就是这个区间被完全覆盖了一次,但是我们要求的是覆盖了两次的情况,那么left_son.len1 + right_son.len1就是 father.len2的长度了。因为整个区间为1则不会往下传,那么子节点的len1则是已经被覆盖了一次,在加父结点的覆盖一次,为两次。
3.当这个区间的cnt == 0 的时候,判断是否为叶子节点。为叶子节点就是0.不是叶子节点的话就可以求,同原先的len1一样,用left_son.len2 + right_son.len2求的就是最终长度。
而此题,与模板题之间的差别就是这个pushup的修改。
代码实现:
# include <iostream>
# include <vector>
# include <algorithm>
using namespace std;
const int N = 2e3 + 10;
struct Node
{
int l,r;
int cnt;
double len1; // 覆盖至少一次的总长度
double len2; // 覆盖至少两次的总长度
}edgs[N * 4];
struct Temp
{
double x1,y1,y2;
int k;
}temp[N];
vector<double> lisan;
int t;
int n;
bool cmp(struct Temp a , struct Temp b) // 将其按照x1小的进行排序
{
return a.x1 < b.x1;
}
int find2(double y)
{
int l = 0 , r = lisan.size() - 1;
while(l < r)
{
int mid = (l + r) / 2;
if(lisan[mid] >= y)
{
r = mid;
}
else
{
l = mid + 1;
}
}
return l;
}
void pushup(int u)
{
if(edgs[u].cnt)
{
edgs[u].len1 = lisan[edgs[u].r + 1] - lisan[edgs[u].l ];
}
else if(edgs[u].l != edgs[u].r)
{
edgs[u].len1 = edgs[2 * u].len1 + edgs[2 * u + 1].len1;
}
else
{
edgs[u].len1 = 0;
}
if(edgs[u].cnt >= 2)
{
edgs[u].len2 = lisan[edgs[u].r + 1] - lisan[edgs[u].l];
}
else if(edgs[u].cnt == 1)
{
edgs[u].len2 = edgs[2 * u].len1 + edgs[2 * u + 1].len1;
}
else if(edgs[u].l != edgs[u].r)
{
edgs[u].len2 = edgs[2 * u].len2 + edgs[2 * u + 1].len2;
}
else
{
edgs[u].len2 = 0;
}
}
void build(int u , int l , int r)
{
edgs[u].l = l , edgs[u].r = r;
if(l == r)
{
return;
}
else
{
int mid = (edgs[u].l + edgs[u].r) / 2;
build(2 * u , l , mid);
build(2 * u +1 , mid +1 , r);
}
}
void modify(int u , int l , int r , int k)
{
if(l <= edgs[u].l && edgs[u].r <= r)
{
edgs[u].cnt += k;
pushup(u);
}
else
{
int mid =(edgs[u].l + edgs[u].r) / 2;
if(l <= mid)
{
modify(2 * u , l , r , k);
}
if(r > mid)
{
modify(2 * u + 1 , l , r , k);
}
pushup(u);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
lisan.clear();
scanf("%d",&n);
int idx = 0;
for(int i = 0; i < n ; i++)
{
double x1,y1,x2,y2;
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
lisan.push_back(y1);
lisan.push_back(y2);
temp[idx++] = {x1,y1,y2,1};
temp[idx++] = {x2,y1,y2,-1};
}
sort(lisan.begin(),lisan.end());
lisan.erase(unique(lisan.begin(),lisan.end()),lisan.end());
sort(temp,temp + idx , cmp);
build(1,0,lisan.size() - 2);
double ans = 0;
for(int i = 0 ; i < idx ; i++)
{
if(i > 0)
{
ans += edgs[1].len2 * (temp[i].x1 - temp[i - 1].x1);
}
modify(1,find2(temp[i].y1),find2(temp[i].y2) - 1,temp[i].k);
}
printf("%.2lf\n",ans);
}
return 0;
}