这个扫描线算法是用线段树完成的,一开始理解有点难度
http://www.cnblogs.com/scau20110726/archive/2013/04/12/3016765.html
算法的思想请看这个blog
然后最近做几个扫描线练习一下(代码还是挺难写的啊,而且变式比较难)
HDU 1542
题意:给你很多矩形,求矩形覆盖的面积
题解:这个就是模板题,理解了思想之后撸一遍模板,cnt是当前区间被覆盖了几次,len是当前区间被覆盖的长度,把x轴的坐标离散化之后,有m个点,所以对应有m-1条边,把这m-1条边对应到线段树里面建树,把m-1条边看成m-1个带权值的点
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 10000+5
#define MAXN 100000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define mid int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem0(x) memset(x,0,sizeof(x))
#define mem1(x) memset(x,-1,sizeof(x))
#define meminf(x) memset(x,INF,sizeof(x))
#define lowbit(x) (x&-x)
const int mod = 1000000007;
const int prime = 999983;
const int INF = 0x3f3f3f3f;
const int INFF = 1e9;
const double pi = 3.141592653589793;
const double inf = 1e18;
const double eps = 1e-10;
//读入外挂
inline int read_int(){
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}while(isdigit(tmp=getchar()));
return ret;
}
struct Node{
double y,x1,x2;
int flag;
bool operator < (const Node &a )const {
return y<a.y;
}
}node[MAX<<1];
struct segment{
int cnt;
double len;
}s[MAX<<3];
double x[MAX<<1];
void pushup(int rt,int l,int r){
if(s[rt].cnt) s[rt].len=x[r+1]-x[l];
else s[rt].len=s[lrt].len+s[rrt].len;
}
void build(int l,int r,int rt){
s[rt].cnt=s[rt].len=0;
if(l==r) return;
mid;
build(lson);
build(rson);
}
void update(int L,int R,int val,int l,int r,int rt){
if(L<=l&&r<=R){
s[rt].cnt+=val;
if(s[rt].cnt>0){
s[rt].len=x[r+1]-x[l];
}
else s[rt].len=s[lrt].len+s[rrt].len;
return ;
}
mid;
if(L<=m) update(L,R,val,lson);
if(R>m) update(L,R,val,rson);
pushup(rt,l,r);
}
int Bsearch(double k,int l,int r){
while(l<=r){
mid;
if(x[m]==k) return m;
else if(x[m]<k) l=m+1;
else r=m-1;
}
}
int main(){
int n;
int kase=0;
while(scanf("%d",&n)&&n){
int t=1;
for(int i=1;i<=n;i++){
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
x[t]=x1;
node[t++]=(Node){y1,x1,x2,1};
x[t]=x2;
node[t++]=(Node){y2,x1,x2,-1};
}
sort(x+1,x+t);
sort(node+1,node+t);
int m=2;
for(int i=2;i<t;i++){
if(x[i]!=x[i-1]) x[m++]=x[i];
}
m--;
build(1,m-1,1);
double ans=0;
for(int i=1;i<t-1;i++){
int l=Bsearch(node[i].x1,1,m);
int r=Bsearch(node[i].x2,1,m)-1;
update(l,r,node[i].flag,1,m-1,1);
ans+=(node[i+1].y-node[i].y)*s[1].len;
}
printf("Test case #%d\nTotal explored area: %.2f\n\n",++kase,ans);
}
return 0;
}
题意:给你很多矩形,计算重叠的面积
题解:看着和上面那题差不多,就是记录区间的覆盖次数,如果覆盖了两次以上,就是重叠
但是没有那么好写,要用len记录覆盖一次的长度,inlen记录覆盖两次及以上的长度
cnt是当前区间覆盖的次数,然后pushup的时候当cnt==0的时候当前区间的len和inlen都等于左右儿子的之和
cnt==1的时候当前区间的len等于区间长度,inlen等于左右儿子的len之和(因为左右儿子的len是覆盖过一次,这会大区间又被覆盖一次,所以左右儿子的len变成了大区间的inlen)
cnt>1的时候inlen等于区间长度
然后感觉并不需要pushdown,。不然看着好复杂,因为cnt只记录一层的覆盖情况,不用pushup,pushdown搞来搞去就清楚了很多
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <sstream>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define MAX 10000+5
#define MAXN 100000+5
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lrt rt<<1
#define rrt rt<<1|1
#define mid int m=(r+l)>>1
#define LL long long
#define ull unsigned long long
#define mem0(x) memset(x,0,sizeof(x))
#define mem1(x) memset(x,-1,sizeof(x))
#define meminf(x) memset(x,INF,sizeof(x))
#define lowbit(x) (x&-x)
const int mod = 1000000007;
const int prime = 999983;
const int INF = 0x3f3f3f3f;
const int INFF = 1e9;
const double pi = 3.141592653589793;
const double inf = 1e18;
const double eps = 1e-10;
//读入外挂
inline int read_int(){
int ret=0;
char tmp;
while(!isdigit(tmp=getchar()));
do{
ret=(ret<<3)+(ret<<1)+tmp-'0';
}while(isdigit(tmp=getchar()));
return ret;
}
struct Node{
double y,x1,x2;
int flag;
bool operator < (const Node &a )const {
return y<a.y;
}
}node[MAX<<1];
struct segment{
int cnt;
double len,inlen;
}s[MAX<<3];
double x[MAX<<1];
void pushup(int l,int r,int rt){
if(s[rt].cnt>1) s[rt].inlen=x[r+1]-x[l];
else if(s[rt].cnt==1){
s[rt].inlen=s[lrt].len+s[rrt].len;
s[rt].len=x[r+1]-x[l];
}
else{
s[rt].inlen=s[lrt].inlen+s[rrt].inlen;
s[rt].len=s[lrt].len+s[rrt].len;
}
}
void build(int l,int r,int rt){
s[rt].cnt=s[rt].len=s[rt].inlen=0;
if(l==r) return;
mid;
build(lson);
build(rson);
}
void update(int L,int R,int val,int l,int r,int rt){
if(L<=l&&r<=R){
s[rt].cnt+=val;
if(s[rt].cnt>1) s[rt].inlen=x[r+1]-x[l];
else if(s[rt].cnt==1){
s[rt].inlen=s[lrt].len+s[rrt].len;
s[rt].len=x[r+1]-x[l];
}
else{
s[rt].inlen=s[lrt].inlen+s[rrt].inlen;
s[rt].len=s[lrt].len+s[rrt].len;
}
return ;
}
mid;
if(L<=m) update(L,R,val,lson);
if(R>m) update(L,R,val,rson);
pushup(l,r,rt);
}
int Bsearch(double k,int l,int r){
while(l<=r){
mid;
if(x[m]==k) return m;
else if(x[m]<k) l=m+1;
else r=m-1;
}
}
int main(){
int T,n;
scanf("%d",&T);
while(T--){
memset(s,0,sizeof(s));
scanf("%d",&n);
int t=1;
for(int i=1;i<=n;i++){
double x1,y1,x2,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
x[t]=x1;
node[t++]=(Node){y1,x1,x2,1};
x[t]=x2;
node[t++]=(Node){y2,x1,x2,-1};
}
sort(x+1,x+t);
sort(node+1,node+t);
int m=2;
for(int i=2;i<t;i++){
if(x[i]!=x[i-1]) x[m++]=x[i];
}
m--;
build(1,m-1,1);
double ans=0;
for(int i=1;i<t-1;i++){
int l=Bsearch(node[i].x1,1,m);
int r=Bsearch(node[i].x2,1,m)-1;
update(l,r,node[i].flag,1,m-1,1);
ans+=(node[i+1].y-node[i].y)*s[1].inlen;
}
printf("%.2lf\n",ans);
}
return 0;
}