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;
}
posted @ 2020-08-04 19:15  GK0328  阅读(106)  评论(0编辑  收藏  举报