题目:http://poj.org/problem?id=1151
http://codeforces.com/contest/610/problem/D
题意:告诉n个矩形的顶点坐标,求面积并。
分析:几篇比较好的介绍线段树扫描线的博客:
http://www.cnblogs.com/kane0526/archive/2013/02/26/2934214.html
http://blog.youkuaiyun.com/xingyeyongheng/article/details/8927732
http://www.cnblogs.com/anhuizhiye/p/3574724.html?utm_source=tuicool&utm_medium=referral
需要注意的是,假设扫描线是从下往上扫描,那么矩形的宽很好求,而底边长需要线段树维护(假如求几处的面积,底边还不一定连续),首先将横坐标离散化,便于将底边插入线段树。pushup的时候,当cover[rt]>0,那么sum[rt]=X[r+1]-X[l],为什么要这样写,而不是sum[rt]=X[r]-X[l]?是为了不漏掉[mid,mid+1]这段区间。所以在插入线段的时候,离散化后的右端点R=Find(s[i].xr,cnt)-1。
代码:
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1e9+7;
const LL MINT = ~0u>>1;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = (1e5+7)*8;
struct seg
{
double xl,xr,h; //线段的左右端点的横坐标,以及线段的高度
int d; //标记是上底边还是下底边
seg(){}
seg(double x1,double x2,double sh,int f):
xl(x1),xr(x2),h(sh),d(f){}
bool operator < (const seg &s)const
{
return h<s.h;
}
}s[maxn];
double sum[maxn]; //区间实际长度
int cover[maxn]; //记录覆盖的次数
double X[maxn]; //离散x坐标
void pushup(int l,int r,int rt)
{
if(cover[rt]) sum[rt]=X[r+1]-X[l];
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 l,int r,int rt)
{
if(L<=l && r<=R)
{
cover[rt]+=c;
pushup(l,r,rt);
return ;
}
int m=(l+r)>>1;
if(L<=m)
update(L,R,c,lson);
if(R>m)
update(L,R,c,rson);
pushup(l,r,rt);
}
int Find(double val,int n)
{
int down=1,mid,up=n;
while(down<=up)
{
mid=(down+up)>>1;
if(X[mid]==val) return mid;
else if(X[mid]>val) up=mid-1;
else down=mid+1;
}
return -1;
}
int main()
{
int n,nCase=0;
while(scanf("%d",&n),n)
{
int num=0;
memset(sum,0,sizeof(sum));
memset(cover,0,sizeof(cover));
for(int i=1;i<=n;i++)
{
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
s[++num]=seg(x1,x2,y1,1);
X[num]=x1;
s[++num]=seg(x1,x2,y2,-1);
X[num]=x2;
}
sort(s+1,s+num+1);
sort(X+1,X+num+1);
int cnt=1;
for(int i=2;i<=num;i++)
if(X[i]!=X[cnt]) X[++cnt]=X[i];
double ans=0;
for(int i=1;i<num;i++)
{
int L=Find(s[i].xl,cnt);
int R=Find(s[i].xr,cnt)-1;
update(L,R,s[i].d,1,cnt,1);
ans+=sum[1]*(s[i+1].h-s[i].h);
}
printf("Test case #%d\n",++nCase);
printf("Total explored area: %.2lf\n\n",ans);
}
return 0;
}
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1e9+7;
const LL MINT = ~0u>>1;
const int maxn = (1e5+7)*8;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct seg
{
int xl,xr,h,d;
seg()=default;
seg(int x1,int x2,int sh,int f):
xl(x1),xr(x2),h(sh),d(f){}
bool operator < (const seg &s)const
{
return h<s.h;
}
}s[maxn];
int sum[maxn];
int cover[maxn];
int X[maxn];
void pushup(int l,int r,int rt)
{
if(cover[rt]) sum[rt]=X[r+1]-X[l];
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 l,int r,int rt)
{
if(L<=l && r<=R)
{
cover[rt]+=c;
pushup(l,r,rt);
return ;
}
int m=(l+r)>>1;
if(L<=m) update(L,R,c,lson);
if(R>m) update(L,R,c,rson);
pushup(l,r,rt);
}
int Find(int val,int n)
{
int down=1,mid,up=n;
while(down<=up)
{
mid=(down+up)>>1;
if(X[mid]==val) return mid;
else if(X[mid]>val) up=mid-1;
else down=mid+1;
}
return -1;
}
void process(int &x1,int &y1,int &x2,int &y2)
{
if(x1==x2)
{
if(y1>y2)
swap(y1,y2);
}
else
{
if(x1>x2)
swap(x1,x2);
}
x2++;
y2++;
}
int main()
{
int n,num=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
process(x1,y1,x2,y2);
s[++num]=seg(x1,x2,y1,1);
X[num]=x1;
s[++num]=seg(x1,x2,y2,-1);
X[num]=x2;
}
sort(s+1,s+num+1);
sort(X+1,X+num+1);
int cnt=1;
for(int i=2;i<=num;i++)
if(X[i]!=X[cnt]) X[++cnt]=X[i];
LL ans=0;
for(int i=1;i<num;i++)
{
int L=Find(s[i].xl,cnt);
int R=Find(s[i].xr,cnt)-1;
update(L,R,s[i].d,1,cnt,1);
ans+=sum[1]*1ll*(s[i+1].h-s[i].h);
}
printf("%lld\n",ans);
return 0;
}