学习笔记 扫描线(面积并)

模板题:https://www.luogu.org/problem/P5490

这个是用于求面积并的扫描线。

显然只有矩形的两边会使答案发生变化。

所以对每一个边做出一个四元组(x,yl,yh,1/-1)

x就是x坐标 yl,yh是这条线的纵坐标,1为左端点,-1为右端点。

 然后就可以用线段树模拟线去扫描。

在线段树里维护两个信息cnt,len。

cnt表示有多少个点覆盖,len表示覆盖的长度。

这样的话就可以ans+=(len(i)*x差)。

代码如下:

#include<bits/stdc++.h>
#define int long long
#define ll long long
using namespace std;
const int maxn=1e6+10;
int n,tot,b[maxn<<1],val[maxn<<1],maxx;
struct n1{
    int x,yl,yh,fl;
}e[maxn<<1];
struct node{
    ll len,cnt;
    #define len(x) t[x].len
    #define cnt(x) t[x].cnt
}t[maxn<<1];
inline bool cmp1(n1 x,n1 y){
    return x.x==y.x ? x.fl<y.fl : x.x<y.x;
}
inline void pushup(int p,int l,int r){
    if(l==r&&r==maxx) return;
    if(cnt(p)) len(p)=val[r+1]-val[l];
    else len(p)=len(p<<1)+len(p<<1|1);
}
inline void add(int p,int l,int r,int x,int y,int d){
    if(x<=l&&r<=y){
        cnt(p)+=d;
        pushup(p,l,r);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) add(p<<1,l,mid,x,y,d);
    if(y>mid) add(p<<1|1,mid+1,r,x,y,d);
    pushup(p,l,r);
}
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        int x,y,xx,yy;
        scanf("%lld%lld%lld%lld",&x,&y,&xx,&yy);
        e[++tot].x=x;b[tot]=y;
        e[tot].yl=y;e[tot].yh=yy;e[tot].fl=1;

        e[++tot].x=xx;b[tot]=yy;
        e[tot].yl=y;e[tot].yh=yy;e[tot].fl=-1;
    }
    sort(b+1,b+1+tot);
    tot=unique(b+1,b+1+tot)-b-1;
    for(int i=1;i<=2*n;i++){
        int h1=lower_bound(b+1,b+1+tot,e[i].yh)-b;
        int h2=lower_bound(b+1,b+1+tot,e[i].yl)-b;
        val[h1]=e[i].yh;val[h2]=e[i].yl;
        e[i].yh=h1;e[i].yl=h2;
        maxx=max(maxx,h1);
    }
    sort(e+1,e+1+2*n,cmp1);
    ll ans=0;
    for(int i=1;i<=2*n;i++){
        add(1,1,2*n,e[i].yl,e[i].yh-1,e[i].fl);
        ans+=len(1)*(e[i+1].x-e[i].x);
    }
    printf("%lld\n",ans);
    //system("pause");
    return 0;
}
扫描二维码关注公众号,回复: 7240041 查看本文章

猜你喜欢

转载自www.cnblogs.com/ChrisKKK/p/11491902.html