【学习笔记】扫描线
一.前言
早就学了扫描线了,但是有一道题当时没做,现在才做,于是就来写写学习笔记。
哎我学习笔记前面咋老是这么多废话啊
二.定义
扫描线其实是一种思想,就是遍历某个值并将其加入数据结构,同时动态地解决一些问题。
听起来很抽象,那就看例题吧。
三.例题
[poj1151]亚特兰蒂斯
求矩形面积并。想象一条线从下往上扫整个平面,就能求出在每个矩形的上下边界处横向覆盖的距离。画出来长这样:

我想这也是这个思想叫扫描线的原因。
因此我们从下往上插入矩形的上下边,在下面加入,在上面删除,顺带统计答案就好了。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define ld long double
#define x1(i) a[i].x1
#define x2(i) a[i].x2
#define y(i) a[i].y
#define tag(i) a[i].tag
#define lid id<<1
#define rid id<<1|1
#define l(id) tr[id].l
#define r(id) tr[id].r
#define cnt(id) tr[id].cnt
#define len(id) tr[id].len
#define lb lower_bound
using namespace std;
const int maxn=1e4+5;
int n,m;
struct line{
ld x1,x2,y;
int tag;
il bool operator<(const line &x){return y<x.y;}
}a[maxn<<1];
ld b[maxn<<1],ans;
struct seg{
int l,r,cnt;
ld len;
}tr[maxn<<3];
il void build(int id,int l,int r){
tr[id]=(seg){l,r,0,0};
if(l==r) return ;
int mid=(l+r)>>1;
build(lid,l,mid),build(rid,mid+1,r);
}
il void pushup(int id){
int l=l(id),r=r(id);
if(cnt(id)) len(id)=b[r+1]-b[l];
else len(id)=len(lid)+len(rid);
}
il void upd(int id,int l,int r,int tag){
if(l(id)>=l and r(id)<=r){
cnt(id)+=tag;
pushup(id);
return ;
}
int mid=(l(id)+r(id))>>1;
if(l<=mid) upd(lid,l,r,tag);
if(r>mid) upd(rid,l,r,tag);
pushup(id);
}
int main(){
for(int T=1;;T++){
scanf("%d",&n);
if(!n) break;
for(int i=1;i<=n;i++){
scanf("%Lf%Lf%Lf%Lf",&x1(i),&y(i),&x2(i),&y(i+n));
x1(i+n)=x1(i),x2(i+n)=x2(i);
tag(i)=1,tag(i+n)=-1;
b[i]=x1(i),b[i+n]=x2(i);
}
n<<=1;
sort(a+1,a+n+1),sort(b+1,b+n+1);
m=unique(b+1,b+n+1)-b-1;
ans=0,build(1,1,m-1);
for(int i=1,l,r;i<n;i++){
l=lb(b+1,b+m+1,x1(i))-b;
r=lb(b+1,b+m+1,x2(i))-b;
upd(1,l,r-1,tag(i));
ans+=len(1)*(y(i+1)-y(i));
}
printf("Test case #%d\nTotal explored area: %.2Lf\n",T,ans);
}
return 0;
}
[IOI1998] [USACO5.5] 矩形周长Picture
求周长,显然直接扫描线就好了。横着跑一遍再竖着跑一遍。
Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define read(x){\
char ch;\
int fu=1;\
while(!isdigit(ch=getchar()))\
fu-=(ch=='-')<<1;\
x=ch&15;\
while(isdigit(ch=getchar()))\
x=(x<<1)+(x<<3)+(ch&15);\
x*=fu;\
}
#define lid tr[id].ls
#define rid tr[id].rs
#define len(id) tr[id].len
#define cnt(id) tr[id].cnt
#define lb lower_bound
using namespace std;
namespace cplx{bool begin;}
const int maxn=5e3+5;
int n,lsh[maxn<<1],tot,num,rt,ans;
int xa[maxn],ya[maxn],xb[maxn],yb[maxn];
struct xian{
int x1,x2,y,tag;
il bool operator<(const xian &x){return y<x.y;}
}a[maxn<<1];
struct seg{int ls,rs,len,cnt;}tr[maxn<<2];
il void build(int &id,int l,int r){
// cout<<l<<" "<<r<<"\n";
id=++num;
len(id)=cnt(id)=lid=rid=0;
if(l==r) return ;
int mid=(l+r)>>1;
build(lid,l,mid);
build(rid,mid+1,r);
}
il void pushup(int id,int l,int r){
if(cnt(id)) len(id)=lsh[r+1]-lsh[l];
else len(id)=len(lid)+len(rid);
}
il void upd(int id,int L,int R,int l,int r,int val){
if(L>=l and R<=r)
return (void)(cnt(id)+=val,pushup(id,L,R));
int mid=(L+R)>>1;
if(l<=mid) upd(lid,L,mid,l,r,val);
if(r>mid) upd(rid,mid+1,R,l,r,val);
pushup(id,L,R);
// cout<<L<<" "<<R<<" "<<cnt(id)<<"\n";
}
il void solve(){
tot=num=rt=0;
for(int i=1;i<=n;i++)
lsh[++tot]=a[i].x1,lsh[++tot]=a[i].x2;
sort(lsh+1,lsh+tot+1);
tot=unique(lsh+1,lsh+tot+1)-lsh-1;
// cout<<tot<<"\n";
// for(int i=1;i<=tot;i++) cout<<lsh[i]<<" ";
// puts("");
n<<=1;
sort(a+1,a+n+1);
build(rt,1,tot-1);
// for(int id=1;id<=num;id++)
// cout<<id<<" "<<lid<<" "<<rid<<" "<<len(id)<<" "<<cnt(id)<<"\n";
// puts("");
for(int i=1,lst=0,t1,t2;i<=n;i++){
t1=lb(lsh+1,lsh+tot+1,a[i].x1)-lsh;
t2=lb(lsh+1,lsh+tot+1,a[i].x2)-lsh;
// cout<<t1<<" "<<t2<<"\n";
upd(rt,1,tot-1,t1,t2-1,a[i].tag);
ans+=abs(len(1)-lst);
lst=len(1);
// cout<<a[i].x1<<" "<<a[i].x2<<" "<<a[i].y<<" "<<a[i].tag<<" ";
// puts("");
// cout<<t1<<" "<<t2<<" "<<lst<<" "<<cnt(1)<<"\n";
}
n>>=1;
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
int main(){
read(n);
// cout<<n<<"\n";
for(int i=1;i<=n;i++){
read(xa[i])read(ya[i]);
read(xb[i])read(yb[i]);
// cout<<xa[i]<<" "<<ya[i]<<" "<<xb[i]<<" "<<yb[i]<<"\n";
}
for(int i=1;i<=n;i++){
a[i].x1=a[i+n].x1=xa[i];
a[i].x2=a[i+n].x2=xb[i];
a[i].y=ya[i],a[i+n].y=yb[i];
a[i].tag=1,a[i+n].tag=-1;
}
solve();
// cout<<n<<"\n";
for(int i=1;i<=n;i++){
a[i].x1=a[i+n].x1=ya[i];
a[i].x2=a[i+n].x2=yb[i];
a[i].y=xa[i],a[i+n].y=xb[i];
a[i].tag=1,a[i+n].tag=-1;
}
solve();
printf("%d",ans);
return 0;
}
[poj2482]窗口的星星
考虑一个星星,能覆盖它的矩形的右上角是在一个区间 \([x,x+W-1]\) 中的。于是扫描线区间修改整体查询最大值即可。
Code
#include<bits/stdc++.h>
#define int long long
#define il inline
#define pb push_back
#define lwrb lower_bound
using namespace std;
namespace asbt{
namespace cplx{bool begin;}
const int maxn=1e4+5;
int n,W,H,lsh[maxn],cnt,rt;
int tr[maxn*70],tag[maxn*70];
int ls[maxn*70],rs[maxn*70];
struct node{
int x,y,c;
}a[maxn];
vector<int> cun[maxn];
il void pushup(int id){
tr[id]=max(tr[ls[id]],tr[rs[id]]);
}
il void pushtag(int id,int v){
tr[id]+=v,tag[id]+=v;
}
il void pushdown(int id){
if(tag[id]){
if(!ls[id]){
ls[id]=++cnt;
tr[cnt]=tag[cnt]=0;
ls[cnt]=rs[cnt]=0;
}
if(!rs[id]){
rs[id]=++cnt;
tr[cnt]=tag[cnt]=0;
ls[cnt]=rs[cnt]=0;
}
pushtag(ls[id],tag[id]);
pushtag(rs[id],tag[id]);
tag[id]=0;
}
}
il void upd(int &id,int L,int R,int l,int r,int v){
if(!id){
id=++cnt;
tr[id]=tag[id]=0;
ls[id]=rs[id]=0;
}
if(L>=l&&R<=r){
pushtag(id,v);
return ;
}
pushdown(id);
int mid=(L+R)>>1;
if(l<=mid){
upd(ls[id],L,mid,l,r,v);
}
if(r>mid){
upd(rs[id],mid+1,R,l,r,v);
}
pushup(id);
}
il void solve(){
int tot=0;
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].c);
lsh[++tot]=a[i].y;
}
sort(lsh+1,lsh+n+1);
tot=unique(lsh+1,lsh+n+1)-lsh-1;
for(int i=1;i<=n;i++){
cun[lwrb(lsh+1,lsh+tot+1,a[i].y)-lsh].pb(i);
}
int ans=0;
cnt=rt=0;
for(int i=1,p=1,q;i<=tot;i++){
for(int j:cun[i]){
upd(rt,0,1ll<<31,a[j].x,a[j].x+W-1,a[j].c);
}
q=lwrb(lsh+1,lsh+tot+1,lsh[i]-H+1)-lsh-1;
while(p<=q){
for(int j:cun[p]){
upd(rt,0,1ll<<31,a[j].x,a[j].x+W-1,-a[j].c);
}
p++;
}
ans=max(ans,tr[rt]);
}
printf("%lld\n",ans);
for(int i=1;i<=tot;i++){
cun[i].clear();
}
}
namespace cplx{
bool end;
il double usdmem(){return (&begin-&end)/1048576.0;}
}
signed main(){
// cout<<cplx::usdmem();
while(~scanf("%lld%lld%lld",&n,&W,&H)){
// puts("666");
solve();
}
return 0;
}
}
signed main(){return asbt::main();}

浙公网安备 33010602011771号