Luogu P5490 [Template] Scanning line

Half a year ago, I heard of a mysterious technology called scan line, but after learning it, you will find that it is actually a use of line segment tree. Among them, the line segment tree of scan line is different from ordinary line segment tree. Each node actually maps the value of 1e9. Secondly, two line segment trees need to be maintained at the same time: flag records whether the current node is completely covered (only the deepest value is recorded without pushup); sum records the length scanned in the current line segment (requires Pushup, but because it only uses sum[1] every time, pushdown is not needed). Another point to note is that the line segment tree is only established based on the left node, so some operations are different from the general line segment tree.

In short, the scanning line principle is not difficult, but there are many details that need to be considered. The code has been marked and cannot be written wrong!

#include <bits/stdc++.h>
#define x first
#define y second
#define mid (l + r >> 1)
#define lo (o << 1)
#define ro (lo | 1)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
const int maxn = 2e5 + 10;
const int inf = 0x3f3f3f3f;
const ll linf = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;
struct tri{int x,y,z;};
struct A
{
    int l,r,h,flag;
}brr[maxn];//arr代表横坐标,brr代表横着的线段信息
int n,tot,arr[maxn],flag[maxn<<2];
ll sum[maxn<<2];

void pushup(int o,int l,int r)
{
    if(flag[o])sum[o]=arr[r+1]-arr[l];
    else if(l==r)sum[o]=0;//是最下边的节点
    else sum[o]=sum[lo]+sum[ro];
}

void add(int ql,int qr,int v,int o=1,int l=1,int r=tot-1)
{
    if(ql<=l&&r<=qr)
    {
        flag[o]+=v;
        pushup(o,l,r);
        return;
    }
    if(ql<=mid)add(ql,qr,v,lo,l,mid);
    if(qr>mid)add(ql,qr,v,ro,mid+1,r);
    //这里的qr可能不是节点值,所以和一般线段树不同
    pushup(o,l,r);
}

int main()
{
    // freopen("in.txt","r",stdin);
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        int x1,y1,x2,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        arr[i*2+1]=x1,arr[i*2+2]=x2;
        brr[i*2]={x1,x2,y1,1};
        brr[i*2+1]={x1,x2,y2,-1};
    }
    sort(brr,brr+2*n,[](A a,A b){return a.h<b.h;});
    sort(arr+1,arr+2*n+1);
    tot=unique(arr+1,arr+2*n+1)-arr-1;
    //将横坐标离散化一下
    unordered_map<int,int>mp;
    for(int i=1;i<=tot;i++)
    {
        mp[arr[i]]=i;
    }
    ll ans=0;
    for(int i=0;i<2*n-1;i++)
    {
        add(mp[brr[i].l],mp[brr[i].r]-1,brr[i].flag);
        //这里不能查找右端点,因为右端点了右边的那个线段
        ans+=sum[1]*(brr[i+1].h-brr[i].h);
    }
    printf("%lld",ans);
    return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_43700916/article/details/104131667