题目:
给n个矩形,求矩形的面积并。n <= 100
分析:
扫描线求面积并模板题。
需要注意的是,线段树记录的不是点,而是边。数轴上若有 1-n 共 n 个点,则会切出 n - 1 条不能再切分的小线段,将这些线段从左至右依次标号为 1 - (n-1)。线段树的每个叶子节点就表示一条小线段。
线段树避免同一段重复加的方法是:对于某一段,如果tag[rt] > 0,则不通过子树来更新值,而是直接计算这一段的值。这样就可避免重复。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 300;
const double EPS = 1e-8;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
struct Edge {
double x1, x2, y;
int f;
Edge () {}
Edge (double x1, double x2, double y, int f): x1(x1), x2(x2), y(y), f(f) {}
bool operator <(const Edge &edge) const{
return y < edge.y;
}
} e[MAXN << 1];
int n;
double x[MAXN];
struct Seg_tree {
double tree[MAXN<<2];
int tag[MAXN<<2];
void build(){
ms(tree,0); ms(tag,0);
}
void pushup(int rt,int l,int r){
if(tag[rt]) tree[rt] = x[r+1] - x[l];
else if(l==r) tree[rt] = 0;
else tree[rt] = tree[rt<<1]+tree[rt<<1|1];
}
void update(int L,int R, int rt,int l,int r,int t){
if(L<=l && R>=r){
tag[rt] += t;
pushup(rt,l,r);
return;
}
if(L <= (l+r)/2) update(L,R,lson,t);
if(R > (l+r)/2) update(L,R,rson,t);
pushup(rt,l,r);
}
}T;
int main() {
// freopen("1.txt","r",stdin);
ios::sync_with_stdio(false);
int Case = 0;
while (cin >> n && n) {
double x1, x2, y1, y2;
int cnt = 0;
for (int i = 0; i < n; i++) {
cin >> x1 >> y1 >> x2 >> y2;
e[++cnt] = Edge(x1, x2, y1, -1);
x[cnt] = x1;
e[++cnt] = Edge(x1, x2, y2, 1);
x[cnt] = x2;
}
sort(e + 1, e + 1 + cnt);
sort(x + 1, x + 1 + cnt);
int m = unique(x + 1, x + 1 + cnt) - x - 1;
T.build();
double ans = 0;
for(int i=1;i<=cnt-1;i++){
int l = lower_bound(x+1,x+1+m,e[i].x1) - x;
int r = lower_bound(x+1,x+1+m,e[i].x2) - x - 1;
T.update(l,r,1,1,m-1,e[i].f);
ans += T.tree[1] * (e[i+1].y - e[i].y);
}
cout << "Test case #" << ++Case << "\n" << fixed << setprecision(2) << "Total explored area: " << ans << "\n\n";
}
return 0;
}