线段树扫描线算法

这个扫描线算法是用线段树完成的,一开始理解有点难度

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;
}



HDU 1255

题意:给你很多矩形,计算重叠的面积

题解:看着和上面那题差不多,就是记录区间的覆盖次数,如果覆盖了两次以上,就是重叠

但是没有那么好写,要用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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值