题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1255
这题的方法在之前的博客有比较详细的描述,这里把需要注意的重点说一下就行了。
https://blog.youkuaiyun.com/godleaf/article/details/86608855
如果题目只是问覆盖至少一次的话,代码基本上不用变,只需要把ans累加的公式改一下就行了,就是两个相邻的垂直线距离,y就是被覆盖的y轴长度。
但是题目要求的是至少2次,那么代码不是说把 cover > 0 改成 cover > 1就行了。 之前的博客有说到cover标记的可信问题。如果cover > 0,那么当前区间就一定能整段取, == 0则不能保证,需要访问左右区间才能知道被覆盖1次的区间长度有多少。如果求覆盖至少2次,那么cover > 1就是可信的,能够整段取,== 0 的情况也能通过左右区间得到覆盖至少2次的区间长度,但是 == 1还存在一种情况,如果当前cover == 1,而子孙节点有 == 1的情况,那么这个子孙节点的区间也是可以取的,但是我们记录了覆盖至少2次的区间长度,当前节点并不知道自己的子孙节点被覆盖1次的区间有多少。讲到这里大概都能猜出怎么做了吧。就是在该线段树扩展一个记录覆盖1次的区间长度,这样就能解决问题了。
在pushup更新区间长度的时候一定要注意不要重复了。当cover == 1 的时候,被覆盖至少两次的长度就是被覆盖2次的长度+被覆盖1次的长度,那么当前区间被覆盖1次的长度就不是一整段区间了,因为有一部分已经加到被覆盖2次的区间长度里面了,所以要除去这些加到被覆盖2次的区间长度。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <set>
using namespace std;
#define lc (cur<<1)
#define rc ((cur<<1)|1)
const int Maxn = 1e3+10;
const int mod = 10007;
typedef long long ll;
struct tree {
int cover;
double len1, len2;
} seg[Maxn<<5];
struct Edge {
int l ,r, val;
double od;
bool operator < (const Edge &a1) const {
return od < a1.od;
}
} edge[Maxn<<1];
double Hash[Maxn<<2], tmp[Maxn<<2];
int L, R, op;
void pushup(int cur, int l, int r) {
if(seg[cur].cover > 1) {
seg[cur].len2 = Hash[r]-Hash[l-1];
seg[cur].len1 = 0;
}
else if(seg[cur].cover == 1) {
if(l == r) {
seg[cur].len2 = 0;
seg[cur].len1 = Hash[r]-Hash[l-1];
}
else {
seg[cur].len2 = seg[lc].len1+seg[rc].len1+seg[lc].len2+seg[rc].len2;
seg[cur].len1 = Hash[r]-Hash[l-1]-seg[cur].len2;
}
}
else if(seg[cur].cover == 0) {
if(l == r) seg[cur].len1 = seg[cur].len2 = 0;
else {
seg[cur].len1 = seg[lc].len1+seg[rc].len1;
seg[cur].len2 = seg[lc].len2+seg[rc].len2;
}
}
}
void updata(int cur, int l, int r) {
if(L <= l && r <= R) {
seg[cur].cover += op;
pushup(cur, l, r);
return;
}
int mid = (l+r)>>1;
if(L <= mid) updata(lc, l, mid);
if(mid+1 <= R) updata(rc, mid+1, r);
pushup(cur, l, r);
}
int main(void)
{
int T, N;
scanf("%d", &T);
while(T--) {
scanf("%d", &N);
for(int i = 0; i < 4*N; ++i) {
scanf("%lf", &tmp[i]);
Hash[i] = tmp[i];
}
sort(Hash, Hash+4*N);
int len = unique(Hash, Hash+4*N)-Hash, m = 0;
for(int i = 0; i < N; ++i) {
int l = lower_bound(Hash, Hash+len, tmp[(i<<2)+1])-Hash+1;
int r = lower_bound(Hash, Hash+len, tmp[(i<<2)+3])-Hash;
edge[++m].l = l; edge[m].r = r; edge[m].od = tmp[(i<<2)];
edge[m].val = 1;
edge[++m].l = l; edge[m].r = r; edge[m].od = tmp[(i<<2)+2];
edge[m].val = -1;
}
sort(edge+1, edge+m+1);
for(int i = 0; i <= 4*len; ++i) seg[i].cover = seg[i].len1 = seg[i].len2 = 0;
double ans = 0;
for(int i = 1; i < m; ++i) {
L = edge[i].l; R = edge[i].r;
op = edge[i].val;
updata(1, 1, len-1);
ans += (seg[1].len2*(edge[i+1].od-edge[i].od));
}
printf("%.2f\n", ans);
}
return 0;
}