1. 程式人生 > 實用技巧 >Luogu5490 【模板】掃描線

Luogu5490 【模板】掃描線

https://www.luogu.com.cn/problem/P5490

掃描線

根據橫座標或縱座標排序另一方向的線段,進入的賦值\(+1\),離開的賦值\(-1\)

注意一下,線段樹的構造中,一個位置表示的是一個間隔,即\(a_1\)表示間隔\([1,2]\),間隔個數為點的個數\(-1\)

如果用點來建,一個點根本無法計算貢獻

\(C++ Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
#define N 200005
using namespace std;
int x,y,_x,_y,n,cnt,cc;
int a1[N],a2[N],b1[N],b2[N],c[N];
ll ans;
struct node
{
    int x,y,_y,t;
    bool operator < (const node b) const
    {
        return x<b.x;
    }
}w[N];
struct T
{
    int cnt,len;
}t[N << 2];  
void push_up(int p,int l,int r)
{
    if (t[p].cnt)
        t[p].len=c[r+1]-c[l]; else
    if (l!=r)
        t[p].len=t[p+p].len+t[p+p+1].len; else
        t[p].len=0;  
}
void add(int p,int l,int r,int x,int y,int z)
{
    if (l>y || r<x)
        return;
    if (x<=l && r<=y)
    {
        t[p].cnt+=z;
        push_up(p,l,r);
        return;
    }
    int mid=(l+r) >> 1;
    add(p+p,l,mid,x,y,z);
    add(p+p+1,mid+1,r,x,y,z);
    push_up(p,l,r);
}
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d%d%d",&x,&y,&_x,&_y);
        w[i+i-1].x=x;
        w[i+i-1].y=y;
        w[i+i-1]._y=_y;
        w[i+i-1].t=1;
        w[i+i].x=_x;
        w[i+i].y=y;
        w[i+i]._y=_y;
        w[i+i].t=-1;
        c[i+i-1]=_y,c[i+i]=y;
    }
    cnt=n << 1;
    sort(c+1,c+cnt+1);
    cc=unique(c+1,c+cnt+1)-c-1;
    sort(w+1,w+cnt+1);
    for (int i=1;i<=cnt;i++)
    {
        w[i].y=lower_bound(c+1,c+cc+1,w[i].y)-c;
        w[i]._y=lower_bound(c+1,c+cc+1,w[i]._y)-c;
    }
    for (int i=1;i<cnt;i++)
    {
        add(1,1,cc,w[i].y,w[i]._y-1,w[i].t);
        ans+=(ll)t[1].len*(w[i+1].x-w[i].x);
    }
    printf("%lld\n",ans);
    return 0;
}