ACwing:1228. 油漆面积
扫描线:
对于扫描线,我们可以将线段树改进成真的线段树,进行操作,这样即可避免离散化,还可以避免在找区间的时候找到单点,这样就会很容易了,所以我们可以对线段树进行一波改进
例如数据:
3
1 5 10 10
3 1 20 20
2 7 15 17
我们可以通过一条平行于y轴的线对y坐标进行扫描,首先我们需要对x坐标进行结构体排序,让x坐标分好块,然后对y坐标进行建线段树,此线段树非平常的线段树,他是不含单点区间的,而且是经过处理,不用离散化的线段树
如图:
如上图所示,我们可以看出这颗线段树是不含单点区间的,而且它的左右端点都是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;
}