您的位置:首页 > 理论基础 > 数据结构算法

扫描线入门

2016-02-25 09:11 344 查看
听说扫描线很牛掰,于是就见识了一下。

之前做过一道扫描线的题,brother,就是判断矩形是否被矩形内部的车攻击到。当时是把矩形拆成出边和入边(竖直的),把所有小于x2的车加进图中,扫[y1,y2]中x最小的车的x.和x1判断比较。然后交换x,y扫一遍

当时只是感觉线段树很神奇,还可以这样搞,后来才知道这种按x2的排序遍历就相当于扫描线。

然后就做了扫描线的入门题。

Weird Advertisement

UVA - 11983
一道扫描线矩形面积并,求被覆盖k次的矩形面积(虽然是点,不过x2+1,y2+1就变成了求面积。  比如只有一个点,把它x2+1,y2+1,就变成了面积为1的正方形)。

理解了大致思路,套了个版.

下面解决一下大致思路吧。

把矩形拆成入边和出边,记录下来,还要打上出入边标记。

按x排序(我是按x拆的,两条边x不同,竖直),然后扫到入边,把[y1,y2]加入,否则把[y1,y2]减去。

要更新>=k的次数。

其实主要复杂一点的是pushup.

一般需要离散化,因为题目往往不会很简单

覆盖K次矩形面积并

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#define LL long long
using namespace std;
LL n,k;
const LL maxn=30000+20;
struct line
{
LL x,y1,y2,flag;
line(LL x,LL y1,LL y2,LL flag)
{
this->x=x;
this->y1=y1;
this->y2=y2;
this->flag=flag;
}
bool operator<(const line &p)const
{
return x<p.x;
}
};
vector<line>L;
LL det[maxn*2];
LL tot=0;
LL find(LL x)
{
return lower_bound(det+1,det+tot+1,x)-det;
}
struct node
{
LL l,r,flag;
LL len[12];//长度为k的有多少个
void set(LL l,LL r,LL flag)
{
this->l=l;
this->r=r;
this->flag=flag;
}
}T[8*maxn];
void pushup(LL u)
{
LL l=T[u].l;
LL r=T[u].r;
for(LL i=0;i<=k;i++)T[u].len[i]=0;
if(l==r)
{
LL t=min(T[u].flag,k);
T[u].len[t]=det[r+1]-det[l];
}
else
{
for(LL i=0;i<=k;i++)
{
LL t=min(T[u].flag+i,k);
T[u].len[t]+=T[u<<1].len[i]+T[u<<1|1].len[i];
}
}
}
void build(LL i,LL l,LL r)
{
T[i].set(l,r,0);
if(l==r)
{
pushup(i);
return ;
}
LL mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
pushup(i);
}
void updata(LL i,LL L,LL R,LL x)
{
LL l=T[i].l;
LL r=T[i].r;
if(l>=L&&r<=R)
{
T[i].flag+=x;
pushup(i);
return ;
}
LL mid=(l+r)>>1;
if(L<=mid)updata(i<<1,L,R,x);
if(R>mid)updata(i<<1|1,L,R,x);
pushup(i);
}
int main()
{
LL yu;
scanf("%lld",&yu);
for(LL cas=1;cas<=yu;cas++)
{
tot=0;
L.clear();
scanf("%lld%lld",&n,&k);
for(LL i=1;i<=n;i++)
{
LL x1,y1,x2,y2;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
det[++tot]=y1;
det[++tot]=y2+1;
L.push_back(line(x1,y1,y2+1,1));
L.push_back(line(x2+1,y1,y2+1,-1));
}
sort(L.begin(),L.end());
sort(det+1,det+tot+1);
LL t=tot;
tot=unique(det+1,det+t+1)-det-1;

build(1,1,tot);
LL ans=0;
for(LL i=0;i<L.size()-1;i++)
{
LL l=find(L[i].y1);
LL r=find(L[i].y2);
updata(1,l,r-1,L[i].flag);
ans+=(L[i+1].x-L[i].x)*T[1].len[k];
}
printf("Case %lld: %lld\n",cas,ans);
}

return 0;
}

这是最裸的矩形面积并。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
LL n;
const LL maxn=100000+20;
const LL k=1;
struct line
{
LL x,y1,y2,flag;
line(LL x,LL y1,LL y2,LL flag)
{
this->x=x;
this->y1=y1;
this->y2=y2;
this->flag=flag;
}
bool operator<(const line&p)const
{
return x<p.x;
}
};
vector<line>L;
LL det[maxn*2];
LL tot;
LL find(LL x)
{
return lower_bound(det+1,det+tot+1,x)-det;
}
struct node
{
LL l,r,flag;
LL len[5];
void set(LL l,LL r,LL flag)
{
this->l=l;
this->r=r;
this->flag=flag;
}
}T[8*maxn];
void pushup(LL i)
{
LL l=T[i].l;
LL r=T[i].r;
for(LL j=0;j<=k;j++)T[i].len[j]=0;
if(l==r)
{
LL t=min(T[i].flag,k);
T[i].len[t]=det[l+1]-det[l];
}
else
{
for(LL j=0;j<=k;j++)
{
LL t=min(T[i].flag+j,k);
T[i].len[t]+=T[i<<1].len[j]+T[i<<1|1].len[j];
}
}
}
void build(LL i,LL l,LL r)
{
T[i].set(l,r,0);
if(l==r)
{
pushup(i);
return ;
}
LL mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
pushup(i);
}
void updata(LL i,LL L,LL R,LL x)
{
LL l=T[i].l;
LL r=T[i].r;
if(l>=L&&r<=R)
{
T[i].flag+=x;
pushup(i);
return ;
}
LL mid=(l+r)>>1;
if(L<=mid)updata(i<<1,L,R,x);
if(R>mid)updata(i<<1|1,L,R,x);
pushup(i);
}
int main()
{
freopen("rectangle.in","r",stdin);
freopen("rectangle.out","w",stdout);
tot=0;
scanf("%I64d",&n);
for(LL i=1;i<=n;i++)
{
LL x1,y1,x2,y2;
scanf("%I64d%I64d%I64d%I64d",&x1,&y1,&x2,&y2);
L.push_back(line(x1,y1,y2,1));
L.push_back(line(x2,y1,y2,-1));
det[++tot]=y1;
det[++tot]=y2;
}
sort(det+1,det+tot+1);
sort(L.begin(),L.end());
LL t=tot;
tot=unique(det+1,det+t+1)-det-1;
build(1,1,tot);
LL ans=0;
for(LL i=0;i<L.size()-1;i++)
{
LL l=find(L[i].y1);
LL r=find(L[i].y2);
updata(1,l,r-1,L[i].flag);
ans+=T[1].len[1]*(L[i+1].x-L[i].x);
}
printf("%I64d\n",ans);
return 0;
}

扫描线大致是一种思想,用数据结构维护。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  扫描线 数据结构