扫描线算法详解
Algorithm Introduction:
lead into
Scanning lines are generally used on graphics, and their literal meaning is very similar, meaning that a line sweeps around the entire graph. They are generally used to solve problems such as graphic area, perimeter, and two-dimensional points.
Algorithm implementation
First.
Our line segment tree is designed to maintain the length of rectangles. We mark the top and bottom edges of each rectangle, with the bottom edge marked as 1 and the top edge marked as -1. Whenever we encounter a rectangle, we know the edge marked as 1, and we add the length of that rectangle. When we scan to -1 and it proves that this edge needs to be deleted, we delete it. By using 1 and -1, we can easily reach this state.
Second
Also note that the line segment tree here does not refer to an endpoint of a line segment, but rather to an interval, so we need to calculate r+1 and r-1.
Finally
Because the data is large, Discretization is required.
practice
Question information (number):
luogu P1856
Algorithm label:Scanning Line
code implementation
tips : Don't worry , there is an explanation in the code
/*******************************************
Note:
*******************************************/
#include <queue>
#include <math.h>
#include <stack>
#include <stdio.h>
#include <iostream>
#include <vector>
#include <iomanip>
#include <string.h>
#include <algorithm>
using namespace std;
//#define int long long
#define ls id<<1//left-son
#define rs id<<1|1//rignt-son
const int N = 5e3 + 10;
int ans,pre;
int n,x,xx,y,yy;
int idx[N<<1];
struct line
{
int l,r,h,cnt;
bool operator < (const line &num)const{
//Overload operator '<', replacing cmp
if(h==num.h)return cnt > num.cnt;
return h < num.h;
//Sort by height (h)
}
}a[N<<1];
struct node
{
int l,r,sum,len,cnt;//CNT represents the number of interval line segments
bool lc,rc;
}tr[N<<2];
void build(int id,int l,int r)
{
tr[id].l=l,tr[id].r=r;
tr[id].lc=tr[id].rc=0;
tr[id].len=tr[id].sum=tr[id].cnt=0;
if(l==r)return;
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
return;
}
void push_up(int id)
{
int l=tr[id].l,r=tr[id].r;
if(tr[id].sum)//If it has already been scanned before
{
tr[id].len=idx[r+1]-idx[l];
tr[id].lc=tr[id].rc=true;
tr[id].cnt=1;
}
else
{
tr[id].len=tr[ls].len+tr[rs].len;
tr[id].lc=tr[ls].lc;
tr[id].rc=tr[rs].rc;
tr[id].cnt=tr[ls].cnt+tr[rs].cnt;
if(tr[ls].rc&&tr[rs].lc)tr[id].cnt--;
/*
If the left son, right endpoint, and right son
The left endpoint is covered, so the middle is
It is a continuous paragraph, so it needs to be -1
*/
}
}
void add(int id,int L,int R,int k)
{
int l=tr[id].l,r=tr[id].r;
if(idx[r+1]<=L||idx[l]>=R)return;
if(L<=idx[l]&&idx[r+1]<=R)
{
tr[id].sum+=k;
push_up(id);
return;
}
add(ls,L,R,k);
add(rs,L,R,k);
push_up(id);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&x,&y,&xx,&yy);
idx[2*i-1]=x,idx[2*i]=xx;
a[2*i-1]=(line){x,xx,y,1};//top
a[2*i]=(line){x,xx,yy,-1};//below
}
//Discretization:
n<<=1;
sort(idx+1,idx+n+1);
sort(a+1,a+n+1);
int tot=unique(idx+1,idx+n+1)-idx-1;
build(1,1,tot-1);
for(int i=1;i<n;i++)
{
add(1,a[i].l,a[i].r,a[i].cnt);
ans+=abs(pre-tr[1].len);
pre=tr[1].len;
ans+=2*tr[1].cnt*(a[i+1].h-a[i].h);
}
ans+=a[n].r - a[n].l;//The last scan line that cannot be enumerated by special judgment
printf("%d\n",ans);
return 0;
}
summarize
Total length of the horizontal side= \(\sum\) | Total length obtained from the previous cut − Total length obtained from the current cut |
Total length of longitudinal edge= \(\sum\) (2 × Number of cut line segments × Sweeped height)
Compared to the area, the horizontal and vertical edges of the perimeter need to be calculated separately
Statement
Borrowed from https://oi-wiki.org/geometry/scanning/
Borrowed from https://www.cnblogs.com/Moomin/p/16101079.html

浙公网安备 33010602011771号