题目:https://nanti.jisuanke.com/t/17313
题意:
确定矩形面积。
#include<bits/stdc++.h>
using namespace std;
double x[2002],y[2002];//最多100个矩形,所以最多只有200条横线或纵线
double a[1002][4];//矩形实际坐标
bool cover[2002][2002];
const double EPS = 1e-7;
int cmp(const void * b,const void * a){//b>a 返回1
if(fabs(*(double* )b-*(double *)a)<EPS)return 0;
else if(*(double* )b-*(double *)a>0)return 1;
else return -1;
}
int main(){
int n,i,k,j,h1,h2,v1,v2;
while(scanf("%d",&n) != EOF){
if(n==0) {
printf("*\n");
break;
}
for(i=0,k=0;i<n;i++,k++){
scanf("%lf%lf%lf%lf",&a[i][0],&a[i][1],&a[i][2],&a[i][3]);
x[k]=a[i][0],y[k]=a[i][1],x[++k]=a[i][2],y[k]=a[i][3];
}
qsort(x,2*n,sizeof(x[0]),cmp);
qsort(y,2*n,sizeof(y[0]),cmp);//将横线,竖线排好序
memset(cover,0,sizeof(cover));//初始时无覆盖区
//对每个矩形,进行一次横纵线的扫描,覆盖范围
//扫描线条数作为下标,离散化
for(i=0;i<n;i++){
k=0;
while(fabs(x[k]-a[i][0])>EPS)k++;h1=k;
k=0;
while(fabs(y[k]-a[i][1])>EPS)k++;v1=k;
k=0;
while(fabs(x[k]-a[i][2])>EPS)k++;h2=k;
k=0;
while(fabs(y[k]-a[i][3])>EPS)k++;v2=k;
//标记该矩形覆盖的区域
for(j=h1;j<h2;j++) //不考虑最右
for(k=v1;k<v2;k++) //不考虑最下
cover[j][k]=true;
}
double sum=0;
//这时再用扫描线真实的位置计算面积,由矩形左下角的点(判断是否覆盖)及四条扫描线确定。
for(i=0;i<2*n-1;i++)
for(j=0;j<2*n-1;j++)
sum+=(cover[i][j]*(x[i+1]-x[i])*(y[j+1]-y[j]));
printf("%d\n", (int)round(sum));
}
}
接下来用线段树做。
用扫描线位置(下标)做权值建线段树。(无需lazy标记)
(加第一条线段时更改的是第一到第二条扫描线的位置,但最后算的是底边为1到3长度的面积)
#include<bits/stdc++.h>
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define ll long long int
using namespace std;
const int maxn = 2000 + 5;
int col[maxn << 2], n, res;
double sum[maxn << 2],X[maxn << 2]; //沿X轴从左往右扫
struct seg{
double l,r,h;
int f; //下边为1,上边为-1,扫描到上边时减去这个区间
seg() {}
seg(double l,double r,double h,int f):l(l),r(r),h(h),f(f) {}
bool operator < (const seg & object) const {
return h < object.h;
}
} S[maxn];
void pushup(int rt,int l,int r){
if(col[rt]) sum[rt]=X[r+1]-X[l]; //r+1是右端点那条
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 rt,int l,int r){
if(l>=L&&r<=R){
col[rt]+=c;
pushup(rt,l,r);
return;
}
int mid=(l+r)>>1;
if(L<=mid) update(L,R,c,lson);
if(R>mid) update(L,R,c,rson);
pushup(rt,l,r);
}
int find(double x){
int l=-1,r=res-1;
while(r>=l){
int mid=(l+r)>>1;
if(X[mid]>=x) r=mid-1;
else l=mid+1;
}
return r+1;
}
int main(){
while(scanf("%d",&n) != EOF){
if(n==0) {
printf("*\n");
break;
}
int cnt=0;
for(int i=0;i<n;i++){
double a,b,c,d;
cin>>a>>b>>c>>d;
S[cnt]=seg(a,c,b,1), X[cnt++]=a;
S[cnt]=seg(a,c,d,-1),X[cnt++]=c;
}
sort(X,X+cnt);
sort(S,S+cnt);
res=unique(X,X+cnt)-X; //扫描线去重
memset(sum,0,sizeof(sum));
memset(col,0,sizeof(col));
double ans=0;
for(int i=0;i<cnt-1;i++){
int l=find(S[i].l); //找下标,放入线段树,相当于离散化
int r=find(S[i].r)-1; //找右端点左边那条,这里不会有2个以上重叠的部分
update(l,r,S[i].f,1,0,res-1);
ans+=sum[1]*(S[i+1].h-S[i].h);
}
printf("%d\n", (int)round(ans)); //四舍五入
}
}