解法:
1.离散化y的坐标,通过二分寻找
2.将x坐标排序,并保存为(x1,y1,y2,1),(x2,y1,y2,-1);
对于矩形左边界+1,对于矩形右边界-1。
3.从小到大扫描每一个x,并且维护当前y轴上的有效长度
ans+=两个x的坐标差*当前y轴上的有效长度
线段树优化:线段树维护的不是点,而是两个点之间的区间
暴力代码:
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 10005;
struct Seg{
double x,y1,y2;
int k;
bool operator < (const Seg &t)const {
return x<t.x;
}
}seg[2*N];
int idx;
int b[N*2];
Seg make_seg(double x,double y1,double y2,int k){
Seg cur;
cur.x = x,cur.y1 = y1,cur.y2 = y2,cur.k = k;
return cur;
}
vector<double> alls;
int n;
int find(double x){
int l = 0,r = alls.size()-1;
while(l<r){
int mid = l+r>>1;
if(alls[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
int main(){
int i,j,k;
int num = 0;
while(cin>>n,n){
memset(b,0,sizeof b);
alls.clear();
memset(seg,0,sizeof seg);
for(i = 1;i<=n;i++){
double x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
seg[++idx] = make_seg(x1,y1,y2,1);
seg[++idx] = make_seg(x2,y1,y2,-1);
alls.push_back(y1);
alls.push_back(y2);
}
sort(seg+1,seg+1+idx);
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
double ans = 0;
for(i = 1;i<idx;i++){
for(j = i;seg[j].x == seg[j+1].x;j++,i++){
int l = find(seg[j].y1);
int r = find(seg[j].y2);
int v = seg[j].k;
for(k = l;k<r;k++){
b[k] += v;
}
}
int l = find(seg[j].y1);
int r = find(seg[j].y2);
int v = seg[j].k;
for(k = l;k<r;k++){
b[k] += v;
}
double res = 0;
for(j = 0;j<alls.size();j++){
if(b[j] > 0){
res += alls[j+1]-alls[j];
}
}
ans += (seg[i+1].x-seg[i].x)*res;
}
num++;
printf("Test case #%d\nTotal explored area: %0.2lf\n\n",num,ans);
}
return 0;
}
线段树优化:
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N = 100005;
struct Seg{
double x,y1,y2;
int k;
bool operator < (const Seg &t)const {
return x<t.x;
}
}seg[2*N];
int idx;
int b[N*2];
Seg make_seg(double x,double y1,double y2,int k){
Seg cur;
cur.x = x,cur.y1 = y1,cur.y2 = y2,cur.k = k;
return cur;
}
struct Node{
int l,r;
double len;//当前区间的有效长度
//区间总长度为alls[r]-alls[l-1]
int v;
}tr[N*4];
vector<double> alls;
int n;
void build(int u,int l,int r){
tr[u].l = l,tr[u].r = r;
if(l != r){
int mid = l + r>>1;
build(2*u,l,mid);
build(2*u+1,mid+1,r);
}
}
void pushup(int u){
if(tr[u].v) tr[u].len = (alls[tr[u].r]-alls[tr[u].l-1]);
else if(tr[u].l != tr[u].r) tr[u].len = tr[2*u].len + tr[2*u+1].len;
else tr[u].len = 0;
}
void update(int u,int l,int r,int k){
if(l<=tr[u].l && tr[u].r<=r){
tr[u].v += k;
pushup(u);
}else{
int mid = tr[u].l + tr[u].r >>1;
if(l<=mid)
update(u*2,l,r,k);
if(r>mid)
update(u*2+1,l,r,k);
pushup(u);
}
}
int find(double x){
int l = 0,r = alls.size()-1;
while(l<r){
int mid = l+r>>1;
if(alls[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}
int main(){
int i,j,k;
int num = 0;
while(cin>>n,n){
memset(b,0,sizeof b);
alls.clear();
memset(seg,0,sizeof seg);
for(i = 1;i<=n;i++){
double x1,x2,y1,y2;
cin>>x1>>y1>>x2>>y2;
seg[++idx] = make_seg(x1,y1,y2,1);
seg[++idx] = make_seg(x2,y1,y2,-1);
alls.push_back(y1);
alls.push_back(y2);
}
sort(seg+1,seg+1+idx);
sort(alls.begin(),alls.end());
alls.erase(unique(alls.begin(),alls.end()),alls.end());
double ans = 0;
build(1,1,alls.size()-1);
for(i = 1;i<=idx;i++){
if(i>1) ans += tr[1].len * (seg[i].x - seg[i-1].x);
update(1,find(seg[i].y1)+1,find(seg[i].y2),seg[i].k);
}
num++;
printf("Test case #%d\nTotal explored area: %0.2lf\n\n",num,ans);
}
return 0;
}