ACwing:1228. 油漆面积 (扫描线:线段树魔改(非离散化))

ACwing:1228. 油漆面积

扫描线:

对于扫描线,我们可以将线段树改进成真的线段树,进行操作,这样即可避免离散化,还可以避免在找区间的时候找到单点,这样就会很容易了,所以我们可以对线段树进行一波改进

例如数据:

3
1 5 10 10
3 1 20 20
2 7 15 17

我们可以通过一条平行于y轴的线对y坐标进行扫描,首先我们需要对x坐标进行结构体排序,让x坐标分好块,然后对y坐标进行建线段树,此线段树非平常的线段树,他是不含单点区间的,而且是经过处理,不用离散化的线段树

如图:

ACwing:1228. 油漆面积 (扫描线:线段树魔改(非离散化))_第1张图片

如上图所示,我们可以看出这颗线段树是不含单点区间的,而且它的左右端点都是y轴的大小,所以我们可以不用离散化

之后就是简单的操作了,我们利用出边和入边的性质去进行区间修改,统计扫描线上的总长度和排好序的区间块相乘即可

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn=2e5+5;
struct line
{
    ll x,y1,y2,fla;
}p[maxn];
ll val[maxn];
bool cmp(line a,line b)
{
    return a.x<b.x;
}
struct node
{
    ll l,r,lazy,len;
}tr[maxn<<3];
void pushup(ll k)
{
    if(tr[k].lazy)
        tr[k].len=tr[k].r-tr[k].l;
    else
        tr[k].len=tr[k<<1].len+tr[k<<1|1].len;
}
void build(ll k,ll l,ll r)
{
    tr[k].l=val[l],tr[k].r=val[r];
    if(r-l<=1)
        return;
    ll mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid,r);
}
void modify(ll k,ll l,ll r,ll w)
{
    if(tr[k].l>=l&&tr[k].r<=r)
    {
        tr[k].lazy+=w;
        pushup(k);
        return ;
    }
    if(tr[k<<1].r>l)
    {
        modify(k<<1,l,r,w);
    }
    if(tr[k<<1|1].l<r)
    {
        modify(k<<1|1,l,r,w);
    }
    pushup(k);
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    ll n,x1,x2,y1,y2,t=0;
    cin>>n;
    for(ll i=1;i<=n;i++)
    {
        cin>>x1>>y1>>x2>>y2;
        p[i*2-1]=(line){x1,y1,y2,1};
        p[i*2]=(line){x2,y1,y2,-1};
        val[++t]=y1,val[++t]=y2;
    }
    sort(p+1,p+1+t,cmp);
    sort(val+1,val+1+t);
    build(1,1,t);
    ll ans=0;
    for(ll i=1;i<t;i++)
    {
         modify(1,p[i].y1,p[i].y2,p[i].fla);
         ans+=tr[1].len*(p[i+1].x-p[i].x);
    }
    cout<<ans<<endl;
}

你可能感兴趣的:(ACM刷题题解,数据结构)