Luogu4198 楼房重建(线段树妙用)

Luogu4198 楼房重建(线段树妙用)

快快乐乐切题,开开心心抄题解

一眼能看出来这是两个\(log\)的做法,但是你永远也想不到第二个放在哪里了

我们从题意得知,我们要求从一开始的极长上升序列

于是如果没有修改的话,我们扫一遍就可以了

然而有修改之后,我们不会做了

但是我们仍然知道要用线段树维护

我们开始思考如何\(pushup\),发现不能直接做,因为不满足可加性

然而,可以满足的是,如果当前区间的最小值满足,那么整个区间都满足

这个性质虽然不会运用到代码中,但是对正解有极大地启发作用

第二只\(log\)\(pushup\)中......

我们对于每一个区间维护一个以左端点开头,斜率递增的最大长度,以及这个最大长度的最后一个斜率

于是我们在\(pushup\)的时候,左区间的长度肯定全要了

再看右区间的最大值合法还是不合法,不合法的话,那就没有右区间的事了,合法的话,我们就开始向下递归

于是我们看递归时当前区间的左区间的最大值,如果满足,那就接着向左区间递归,把右区间的长度全加上

不满足的话,那就去右区间找就行了

code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
int read(){
    int s=0,t=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
    return s*t;
}
const int N=1e5+5;
int n,m;
struct XDS{
    #define ls x<<1
    #define rs x<<1|1
    int len[N*4],mxx[N*4],mxy[N*4];
    int get(int x,int mx,int my,int l,int r){
        if(mx*mxy[x]<=mxx[x]*my)return 0;
        if(l==r)return 1;int mid=l+r>>1;
        if(mx*mxy[ls]<=mxx[ls]*my)return get(rs,mx,my,mid+1,r);
        return get(ls,mx,my,l,mid)+len[x]-len[ls];
    }
    void pushup(int x,int l,int r){
        len[x]=len[ls];mxx[x]=mxx[ls];mxy[x]=mxy[ls];
        if(!len[ls]){mxx[x]=mxx[rs];mxy[x]=mxy[rs];len[x]=len[rs];return ;}
        if(mxx[ls]*mxy[rs]<=mxx[rs]*mxy[ls]||!len[rs])return ;
        mxx[x]=mxx[rs];mxy[x]=mxy[rs];int mid=l+r>>1;
        // cout<<x<<" "<<l<<" "<<r<<" "<<mxx[ls]<<" "<<mxy[ls]<<endl;
        len[x]+=get(rs,mxx[ls],mxy[ls],mid+1,r);
    }
    void ins(int x,int l,int r,int pos,int my){
        if(l==r){
            mxx[x]=l;mxy[x]=my;
            if(!my)len[x]=0;
            else len[x]=1;
            return ;
        }
        int mid=l+r>>1;
        if(pos<=mid)ins(ls,l,mid,pos,my);
        else ins(rs,mid+1,r,pos,my);
        pushup(x,l,r);return ;
    }
    #undef ls
    #undef rs
}xds;
signed main(){
    n=read();m=read();
    while(m--){
        int x=read(),y=read();
        xds.ins(1,1,n,x,y);
        printf("%lld\n",xds.len[1]);
    }
}
posted @ 2021-12-16 21:00  fengwu2005  阅读(85)  评论(1编辑  收藏  举报