题解 P5490 【【模板】扫描线】

题解 P5490 【【模板】扫描线】

题解

看了怎么多题解,竟然没有一篇是下传标记的。

我来写一份常规的下传标记的做法。

我们需要维护区间最小值和最小值的个数

对于一个询问,如果区间最小值>0,那么返回区间长长度,否则说明区间有些地方是0,那么答案就是区间长度-最小值个数(长度)

然后就是普通线段树操作了,不需要标记用优化。

代码

#include<bits/stdc++.h>
using namespace std;
#define next Next
#define last Last
#define int long long
const int N=1e6+5;
int n,gs,len,b[N],mi[N*4],lazy[N*4],sum[N*4],Len[N*4];
struct node{
    int val,l,r,opt;
}a[N];
/*char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}*/
#define gc getchar
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
void pushup(int nod)
{
    mi[nod]=min(mi[nod*2],mi[nod*2+1]);
    if(mi[nod]==mi[nod*2])sum[nod]=sum[nod*2];
    else sum[nod]=0;
    if(mi[nod]==mi[nod*2+1])sum[nod]+=sum[nod*2+1];
}
void pushdown(int nod)
{
    if(lazy[nod]==0)return;
    mi[nod*2]+=lazy[nod];
    mi[nod*2+1]+=lazy[nod];
    lazy[nod*2]+=lazy[nod];
    lazy[nod*2+1]+=lazy[nod];
    lazy[nod]=0;   
}
void build(int nod,int l,int r)
{
    Len[nod]=b[r+1]-b[l];
    if(l==r)
    {
        sum[nod]=Len[nod];
        return;
    }
    int mid=(l+r)/2;
    build(nod*2,l,mid);
    build(nod*2+1,mid+1,r);
    pushup(nod);
}
void change(int nod,int l,int r,int L,int R,int val)
{
    if(l==L&&r==R)
    {
        mi[nod]+=val;
        lazy[nod]+=val;
        return;
    }
    pushdown(nod);
    int mid=(l+r)/2;
    if(R<=mid)change(nod*2,l,mid,L,R,val);
    else if(L>mid)change(nod*2+1,mid+1,r,L,R,val);
    else{
        change(nod*2,l,mid,L,mid,val);
        change(nod*2+1,mid+1,r,mid+1,R,val);
    }
    pushup(nod);
}
int find(int nod,int l,int r,int L,int R)
{
    if(l==L&&r==R)
    {
        if(mi[nod]>0)return Len[nod];
        return Len[nod]-sum[nod];
    }
    pushdown(nod);
    int mid=(l+r)/2;
    if(R<=mid)return find(nod*2,l,mid,L,R);
    else if(L>mid)return find(nod*2+1,mid+1,r,L,R);
    else return find(nod*2,l,mid,L,mid)+find(nod*2+1,mid+1,r,mid+1,R);
    pushup(nod);
}
bool cmp(node a,node b)
{
    return a.val<b.val;
}
signed main()
{
    n=read();
    for(int i=1;i<=n;i++)
    {
        int x1=read(),y1=read(),x2=read(),y2=read();
        a[++gs]=(node){x1,y1,y2,1};
        a[++gs]=(node){x2,y1,y2,-1};
        b[++len]=y1;
        b[++len]=y2;
    }
    sort(b+1,b+len+1);
    len=unique(b+1,b+len+1)-b-1;
    build(1,1,len-1);
    for(int i=1;i<=gs;i++)
    {
        a[i].l=lower_bound(b+1,b+len+1,a[i].l)-b;
        a[i].r=lower_bound(b+1,b+len+1,a[i].r)-b;
    }
    sort(a+1,a+gs+1,cmp);
    int ans=0;
    for(int i=1;i<gs;i++)
    {
        if(a[i].l<a[i].r)change(1,1,len-1,a[i].l,a[i].r-1,a[i].opt);
        ans=ans+find(1,1,len-1,1,len-1)*(a[i+1].val-a[i].val);
    }
    cout<<ans;
}
xuxuxuxuxu 文章被收录于专栏

信息学竞赛

全部评论

相关推荐

头像
2025-12-27 13:01
三峡大学 C++
点赞 评论 收藏
分享
02-01 12:05
复旦大学 Java
腾讯的提前批大概率应该是没有笔试的,但是这个时候有相当部分的同学简历估计都没有准备好,没准备好的同学也不用急,大部分都是3月之后开,这个时候开的绝大多数都是神仙打架,问的东西也比较难,打算投递的同学也多看下计算机网络和操作系统,腾讯对这部分的知识问的比较多。另外多刷下牛客的热门题库,刷题注意刷ACM模式,和牛客的周赛题,腾讯有的部门会从这里面出原题。我是@程序员花海关注我,带你了解更多校招资讯!
程序员花海:还没有来得及准备的同学可以看下学习路线:https://www.nowcoder.com/discuss/824693499982315520?sourceSSR=users算法题:https://www.nowcoder.com/feed/main/detail/20e7a999fa04485b88340a274411ca0d?sourceSSR=users八股文:https://www.nowcoder.com/discuss/833102362771251200?sourceSSR=users简历书写方式:https://www.nowcoder.com/discuss/839907820706205696?sourceSSR=users都是以前在牛客发的文章~
软开人,秋招你打算投哪些...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务