会当凌绝顶,一览众山小

题目(划重点)

  • 登山顺序不一定从左到右,是按照给出山峰的顺序
  • 找到左边第一个大于当前山峰的山峰的坐标,修改他
  • 如果右边没有大于当前山峰的,找到离当前山峰最近的最矮山峰,修改它

分析

  • 线段树实现
  • 首先,由于下标范围过大,离散一波。然后建一棵线段树,存储最大值和最小值。
  • 左边:假设当前是第i座山,映射过去的位置是pos(离散化),二分[1,pos]区间,找到最近的一个大于当前高度的山
  • 右边:同理。假设映射的位置是pos,先求出区间[pos+1,n]的最大值判断需不需要修改。若是需要,则二分[pos+1,n]
    区间,找到最近的一个最小值

代码

#include<bits/stdc++.h>
#define ls now<<1
#define rs now<<1|1
using namespace std;
const int N=2e5+10;

int n,cnt;
int h[N],ma[N<<2],mi[N<<2],b[N];

struct nkl{int x,y;}s[N];

inline void upd(int now)
{
    ma[now]=max(ma[ls],ma[rs]);
    mi[now]=min(mi[ls],mi[rs]);
}

inline void build(int now,int l,int r)
{
    if(l==r)
    {
        mi[now]=ma[now]=h[l];
        return ;
    }

    int mid=(l+r)>>1;
    build(ls,l,mid),build(rs,mid+1,r);

    upd(now);
}

inline int askmx(int now,int l,int r,int x,int y)
{
    if(l>=x&&r<=y) return ma[now];

    int mid=(l+r)>>1,ret=-1e9;
    if(x<=mid) ret=askmx(ls,l,mid,x,y);
    if(mid<y) ret=max(ret,askmx(rs,mid+1,r,x,y));

    return ret;
}

inline int askmi(int now,int l,int r,int x,int y)
{
    if(l>=x&&r<=y) return mi[now];

    int mid=(l+r)>>1,ret=1e9;
    if(x<=mid) ret=askmi(ls,l,mid,x,y);
    if(mid<y) ret=min(ret,askmi(rs,mid+1,r,x,y));

    return ret;
}

inline void ud(int now,int l,int r,int x,int z)
{
    if(l==r)
    {
        ma[now]=mi[now]=z;
        return ;
    }

    int mid=(l+r)>>1;
    if(x<=mid) ud(ls,l,mid,x,z);
    else ud(rs,mid+1,r,x,z);

    upd(now);
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d%d",&s[i].x,&s[i].y);
        b[i]=s[i].x;
    }sort(b+1,b+n+1);

    for (int i=1;i<=n;i++)
    {
        int p=lower_bound(b+1,b+n+1,s[i].x)-b;
        h[p]=s[i].y;
    }build(1,1,n);

    for (int i=1;i<=n;i++)
    {
        int pos=lower_bound(b+1,b+n+1,s[i].x)-b;
        //位置
        //第一步:找到左边第一个大于当前高度的
        int xx=askmx(1,1,n,1,pos);
        if(xx>h[pos])
        {
            int l=1,r=pos,ans=0;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                xx=askmx(1,1,n,mid,pos);
                if(xx>h[pos]) ans=mid,l=mid+1;
                else r=mid-1;
            }
            h[ans]=h[pos];ud(1,1,n,ans,h[pos]);
        }

        if(pos==n) continue;

        int yy=askmx(1,1,n,pos+1,n);
        if(yy<=h[pos])
        {
            int kp=askmi(1,1,n,pos+1,n);//最小的那个
            int l=pos+1,r=n,ans=0;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                yy=askmi(1,1,n,pos+1,mid);
                if(yy==kp) ans=mid,r=mid-1;
                else l=mid+1;
            }
            h[ans]=h[pos];ud(1,1,n,ans,h[pos]);
        }
    }

    for (int i=1;i<=n;i++)
    {
        int x=lower_bound(b+1,b+n+1,s[i].x)-b;
        printf("%d ",h[x]);
    }

    return 0;
}