这个扫描线算法是用线段树完成的,一开始理解有点难度
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; }