题目:http://acm.hdu.edu.cn/showproblem.php?pid=1255
题意:给你n个矩形,要你计算这些矩形被覆盖两次以上部分的面积和。
做法:
刚学的扫描线,留个板子和参考链接,很多地方容易出细节问题。
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn=1005;
struct seg{
double l,r,h;
int v;
}se[maxn*2];
int num[maxn<<3];
double once[maxn<<3],twice[maxn<<3];
bool cmp(seg a,seg b){
return a.h<b.h;
}
int n,k,m;
double X[maxn*2];
int fin(double x){
int l=1,r=m;
while(l<=r){
int mid=(l+r)/2;
if(X[mid]==x) return mid;
if(X[mid]>x) r=mid-1;
else l=mid+1;
}
return -1;
}
void deal(int rt,int l,int r){
//deal只更新一块区域,上面的是跟着更新的但是不会增加num值
if(num[rt]) //如果有覆盖,则一次覆盖的就是左右差
//注意 这里的(] 是为了保证连续区间不会重复加
once[rt]=X[r+1]-X[l];
else if (l==r)//如果是叶子结点 那么就是0
once[rt]=0;
else
once[rt]=once[lson]+once[rson];
if(num[rt]>1)
twice[rt]=X[r+1]-X[l];
else if(l==r)
twice[rt]=0;
else if(num[rt]==1)
twice[rt]=once[lson]+once[rson];
else
twice[rt]=twice[lson]+twice[rson];
}
void update(int ql,int qr,int l,int r,int v,int rt){
if(l>=ql&&r<=qr){
num[rt]+=v;
deal(rt,l,r);
return ;
}
int mid=(l+r)/2;
if(ql<=mid) update(ql,qr,l,mid,v,lson);
if(qr>mid) update(ql,qr,mid+1,r,v,rson);
deal(rt,l,r);
}
int main(){
int t;
cin>>t;
while(t--){
scanf("%d",&n);
k=1;
for(int i=1;i<=n;i++,k+=2){
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
X[k]=x1,X[k+1]=x2;
se[k].l=x1,se[k].r=x2,se[k].h=y1,se[k].v=1;
se[k+1].l=x1,se[k+1].r=x2,se[k+1].h=y2,se[k+1].v=-1;
}
k--;
sort(se+1,se+1+k,cmp);
sort(X+1,X+1+k);
X[0]=-1;
m=0;
for(int i=1;i<=k;i++){
if(X[i]!=X[i-1]) X[++m]=X[i];
}
memset(num,0,sizeof(num));
memset(once,0,sizeof(once));
memset(twice,0,sizeof(twice));
double ans=0;
for(int i=1;i<k;i++){
int l=fin(se[i].l);
int r=fin(se[i].r)-1;
update(l,r,1,m,se[i].v,1);
ans=(ans+twice[1]*(se[i+1].h-se[i].h));
//printf("i=%d ans=%.2f\n",i,ans);
}
printf("%.2f\n",ans);
}
return 0;
}