线段树扫描线

大佬的博客

看了好几天,感觉自己看懂了。

https://blog.csdn.net/riba2534/article/details/76851233这个大佬内部有图,可以手动纸上跟着画一下加深理解

扫描线可以水平扫,也可以垂直扫,这里我说一下垂直扫吧。

题目给出的坐标为浮点数,那么我们将所有的y坐标排序离散化后,假设共有m个不同的坐标值,设为val[1~m]。

那么这m个不同的y值就可以将一条垂直x轴的直线划分为m-1段吧(超出最大的y,与小于最小的y的地方不算),

那么为这m-1个线段标号分别为1~m-1,线段树维护的就是这m-1根线段被覆盖了多少次。

就比如节点[1,1]就表示的是线段1,长度为val[2]-val[1]。[2,5]就表示的是从2~5包含的所有线段,长度为val[6]-val[2]。

将每个矩形拆成两个四元组 (x1,y1,y2,1) (x2,y1,y2,-1) 按照x从小到大排序逐次将2*n-1条加入线段树(不加入最后一条)

线段树中的每个节点都表示不同的含义,不同于普通的线段树需要将子树的信息更新到叶子节点。

不下传标记

 

一道裸题:https://www.acwing.com/problem/content/249/

#include<bits/stdc++.h>
using namespace std;

const int maxn=209;

double y[maxn];


int cnt[maxn<<2|1];
double len[maxn<<2|1];
int m;
struct Node{
    double y1,y2,h;
    int v;
    bool operator <(const Node& x)const{
        return h<x.h;
    }
}a[maxn];

void quchong(int n){
    sort(y+1,y+n+1);
    m=unique(y+1,y+n+1)-(y+1);
}
int getid(double x){
    return lower_bound(y+1,y+m+1,x)-(y+1)+1;
}

void pushup(int l,int r,int k){
    if(cnt[k]) len[k]=y[r+1]-y[l];
    else if(l==r) len[k]=0;//叶子节点表示线段l+1这一段,若标记为0,说明该线段已经剔除掉或者还未使用;
    else len[k]=len[k<<1]+len[k<<1|1];
//若标记为0,非叶子节点的话,只能说明线段从l~r+1没有被全部使用,
//那么就需要从左右子树获取l~r+1被覆盖了多少;
//比如我更新了[1,1]后,[1,2]的标记仍为0,但是其长度是val[2]-val[1]
}

void build(){
    memset(cnt,0,sizeof(cnt));
    memset(len,0,sizeof(len));
    memset(y,0,sizeof(y));
}

void updata(int L,int R,int l,int r,int k,int v){
    if(l>=L&&r<=R){
        cnt[k]+=v;
        pushup(l,r,k);
        return ;
    }
    int mid=(l+r)>>1;
    if(L<=mid) updata(L,R,l,mid,k<<1,v);
    if(R>mid) updata(L,R,mid+1,r,k<<1|1,v);
    pushup(l,r,k);

}
void prin(){
    for(int i=1;i<=20;++i) cout<<len[i]<<" ";
    cout<<endl;

}

int main(){
    int n;
    int num=0;
    while(scanf("%d",&n)!=EOF&&n){
        double x1,y1,x2,y2;
        build();

        for(int i=1;i<=n;++i){
            int k=(i<<1);
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            a[k-1].y1=y1,a[k-1].y2=y2,a[k-1].h=x1;
            a[k-1].v=1;
            a[k].y1=y1,a[k].y2=y2,a[k].h=x2;
            a[k].v=-1;
            y[k-1]=y1,y[k]=y2;
        }
        n<<=1;
        sort(a+1,a+1+n);
        quchong(n);
        double ans=0;
        for(int i=1;i<n;++i){
            int l=getid(a[i].y1),r=getid(a[i].y2)-1;
            //cout<<l<<" "<<r<<endl;
            updata(l,r,1,m-1,1,a[i].v);
            ans+=len[1]*(a[i+1].h-a[i].h);
            //cout<<ans<<endl;
            //prin();
        }
        printf("Test case #%d\nTotal explored area: %.2f\n\n", ++num, ans);

    }
    return 0;
}

这位大佬有讲面积交:https://www.cnblogs.com/lxjshuju/p/7040186.html

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn=2009;
double y[maxn];
int m;
void quchong(int n){
    sort(y+1,y+1+n);
    m=unique(y+1,y+1+n)-(y+1);
}

int getid(double x){
    return lower_bound(y+1,y+1+m,x)-(y+1)+1;
}

struct Node{
    double h,y1,y2;
    int v;
    bool operator <(const Node& x)const{
        return h<x.h;
    }
}a[maxn];


double len1[maxn<<2|1],len2[maxn<<2|1];
int cnt[maxn<<2|1];

void build(){
    memset(len1,0,sizeof(len1));
    memset(len2,0,sizeof(len2));
    memset(cnt,0,sizeof(cnt));
}
void pushup(int l,int r,int k){
    if(cnt[k]) len1[k]=y[r+1]-y[l];
    else if(l==r) len1[k]=0;
    else len1[k]=len1[k<<1]+len1[k<<1|1];

    if(cnt[k]>=2) len2[k]=y[r+1]-y[l];
    else if(l==r) len2[k]=0;
    else if(cnt[k]==1) len2[k]=len1[k<<1]+len1[k<<1|1];
    else len2[k]=len2[k<<1]+len2[k<<1|1];
}

void updata(int L,int R,int l,int r,int k,int v){
    if(l>=L&&r<=R){
        cnt[k]+=v;
        pushup(l,r,k);
        return ;
    }
    int mid=(l+r)>>1;
    if(L<=mid) updata(L,R,l,mid,k<<1,v);
    if(R>mid) updata(L,R,mid+1,r,k<<1|1,v);
    pushup(l,r,k);
}

int main(){
    int t;
    scanf("%d",&t);
    int n;
    double x1,x2,y1,y2;
    while(t--){
        build();
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            int k=(i<<1);
            a[k-1].h=x1,a[k-1].y1=y1,a[k-1].y2=y2,a[k-1].v=1;
            a[k].h=x2,a[k].y1=y1,a[k].y2=y2,a[k].v=-1;
            y[k-1]=y1,y[k]=y2;
        }
        double res=0;
        n<<=1;
        sort(a+1,a+1+n);
        quchong(n);

        for(int i=1;i<n;++i){
            int l=getid(a[i].y1),r=getid(a[i].y2)-1;
            //cout<<l<<" "<<r<<endl;
            updata(l,r,1,m-1,1,a[i].v);
            res+=len2[1]*(a[i+1].h-a[i].h);
        }
        printf("%.2f\n",res);


    }

    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值