题意:给你若干个矩形,求被矩形覆盖过至少两次的区域的面积;
思路:典型的扫描线的题目,唯一需要处理的问题是如何判断覆盖次数,我第一次做的时候是用了一个lazy数组来表示当前区间被覆盖的此数,由此而配套了一个pushDown函数,用于处理lazy[]和cnt[]间的传递,今天重做的时候发现cnt[]与lazy[]基本相同,由此想到之前的lazy[]类似于一个状态值,但我们并不需要用一个数组来储存它,在query()中加入一个参数即可
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cstring>
using namespace std;
int cnt[40000];
double Hash[40000], sum[40000];
struct line
{
double x, y1, y2;
int type;
bool operator < (line A){ return x < A.x;}
}Line[40000];
void pushUp(int rt,int l,int r)
{
if(cnt[rt]) sum[rt] = Hash[r+1] - Hash[l];
else if(l == r) sum[rt] = 0;
else sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void update(int L,int R,int C,int l,int r,int rt)
{
if(L <= l && r <= R){
cnt[rt] += C;
pushUp(rt,l,r);
return ;
}
int m = (l+r)>>1;
if(L <= m) update(L,R,C,l,m,rt<<1);
if(m < R) update(L,R,C,m+1,r,rt<<1|1);
pushUp(rt,l,r);
}
double query(int l,int r,int rt,int t) //t>=2即表示覆盖超过两次
{
if(t + cnt[rt] >= 2)
return sum[rt];
if(l == r) return 0;
int m = (l+r)>>1;
double ans = 0;
ans += query(l,m,rt<<1,t+cnt[rt]);
ans += query(m+1,r,rt<<1|1,t+cnt[rt]);
return ans;
}
int main()
{
int T, n, pos;
double x1, y1, x2, y2, ans;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
ans = pos = 0;
memset(sum,0, sizeof sum);
memset(cnt,0,sizeof cnt);
for(int i = 0; i < n; ++i){
scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2);
Line[i<<1] = {x1,y1,y2,1};
Line[i<<1|1] = {x2,y1,y2,-1};
Hash[pos++] = y1; Hash[pos++] = y2;
}
sort(Line,Line+(n<<1));
sort(Hash,Hash+pos);
pos = unique(Hash,Hash+pos) - Hash - 1;
for(int i = 0; i < (n<<1) - 1; ++i){
int L = lower_bound(Hash,Hash+pos+1,Line[i].y1) - Hash;
int R = lower_bound(Hash,Hash+pos+1,Line[i].y2) - Hash;
update(L,R-1,Line[i].type,0,pos,1);
double t = query(0,pos,1,0);
ans += t * (Line[i+1].x - Line[i].x) + 1e-8;
}
printf("%.2f\n", ans);
}
return 0;
}