牛客小白月赛28—E会当凌绝顶,一览众山小(线段树)

链接:https://ac.nowcoder.com/acm/contest/7412/E
来源:牛客网

题目描述
牛牛最喜欢爬山了,他喜欢站在最高的山峰上展望。
牛牛来到山脚下,看到这里一共有 n 个山峰,每个山峰有一个坐标 x i x_i xi和高度 h i h_i hi(n个山峰在一条直线上),参差不齐,心里瞬间很不舒服。他最喜欢看到的山峰是从左到右高度依次增大,所以牛牛就要使用魔法了。当牛牛登上第 i 个山峰的时候,他要用乾坤大挪移把当前山峰左边 ( x j < x i ) (x_j<x_i) (xj<xi)第一个比这个山峰严格大的山峰变得和当前山峰一样高,如果右边 ( x j > x i ) (x_j>x_i) (xj>xi)没有山峰比他严格大,牛牛还是很不满足,他要把右边最小的山峰变成和当前山峰一样大(如果有多个最小的,变最左边的一个),当牛牛从第 n 个山峰下来的时候,看到这一场面,心中很是满足,但是他不知道自己把山峰都变成什么样了,想要知道每个山峰的新高度 h i h_i hi ,你能告诉他吗?
注意:登山顺序不一定从左到右,是按照给出山峰的顺序

输入描述:
第一行有一个正整数 n ( n ≤ 2 × 1 0 5 ) n(n \leq 2×10^5) nn2×105,表示有 n 座山峰
接下来 n 行每行有两个整数x , h ( 1 0 − 9 ≤ x ≤ 1 0 9 , 1 ≤ h ≤ 1 0 9 ) h(10^{-9} \leq x\leq 10^9,1\leq h\leq 10^9) h109x109,1h109(保证每个 x 都不相同)

输出描述:
输出一行,n 个数,分别表示第 i 个山峰最后的高度 h

思路:线段树区间查询、单点修改,注意:结果要按照输入的顺序输出。

1、查询区间第一个大于val的数的位置:

int query_max(int root,int l,int r,int ll,int rr,int val)
//ll~rr中比val大的第一个数的位置
{
    if(tree[root].mmax<=val)return 0;
    if(l==r){
        return l;
    }
    int pos=0;
    if(rr<=mid)
        pos=query_max(chl,l,mid,ll,rr,val);
    else if(ll>mid)
        pos=query_max(chr,mid+1,r,ll,rr,val);
    else{
        pos=query_max(chr,mid+1,r,mid+1,rr,val);
        if(!pos)pos=query_max(chl,l,mid,ll,mid,val);
    }
    return pos;
}

2、查询区间最小值及其位置

PII query_min(int root,int l,int r,int ll,int rr)
//ll~rr中最小值的位置
{
    if(l==ll&&r==rr){
        return make_pair(tree[root].mmin,tree[root].pos);
    }
    if(rr<=mid)
        return query_min(chl,l,mid,ll,rr);
    else if(ll>mid)
        return query_min(chr,mid+1,r,ll,rr);
    else return min(query_min(chl,l,mid,ll,mid),query_min(chr,mid+1,r,mid+1,rr));
}

代码:

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<string>
#include<queue>
using namespace std;
#define LL long long
#define uLL unsigned long long
#define PII pair<int,int>
#define mid ((l + r)>>1)
#define chl (root<<1)
#define chr (root<<1|1)
const int manx = 2e5 + 10;
const int INF = 0x3fffffff;
const int mod = 1e4+7;

int n,x,h;
int num[manx],lis[manx],a[manx],b[manx],tmp[manx];
struct node
{
    int mmax;
    int mmin,pos;
}tree[manx<<2];
void eval(int root)
{
    tree[root].mmax=max(tree[chl].mmax,tree[chr].mmax);
    tree[root].mmin=min(tree[chl].mmin,tree[chr].mmin);
    tree[root].pos=tree[chl].mmin<=tree[chr].mmin?tree[chl].pos:tree[chr].pos;
}
void build_tree(int root,int l,int r)
{
    if(l==r){
        tree[root].pos=l;
        tree[root].mmax=tree[root].mmin=num[l];
        return;
    }
    build_tree(chl,l,mid);
    build_tree(chr,mid+1,r);
    eval(root);
}
void change(int root,int l,int r,int pos,int val)
{
    if(l==r){
        num[l]=tree[root].mmax=tree[root].mmin=val;
        return;
    }
    if(pos<=mid)
        change(chl,l,mid,pos,val);
    else change(chr,mid+1,r,pos,val);
    eval(root);
}
int query_max(int root,int l,int r,int ll,int rr,int val)//ll~rr中比val大的第一个数的位置
{
    if(tree[root].mmax<=val)return 0;
    if(l==r){
        return l;
    }
    int pos=0;
    if(rr<=mid)
        pos=query_max(chl,l,mid,ll,rr,val);
    else if(ll>mid)
        pos=query_max(chr,mid+1,r,ll,rr,val);
    else{
        pos=query_max(chr,mid+1,r,mid+1,rr,val);
        if(!pos)pos=query_max(chl,l,mid,ll,mid,val);
    }
    return pos;
}
PII query_min(int root,int l,int r,int ll,int rr)//ll~rr中最小值的位置
{
    if(l==ll&&r==rr){
        return make_pair(tree[root].mmin,tree[root].pos);
    }
    if(rr<=mid)
        return query_min(chl,l,mid,ll,rr);
    else if(ll>mid)
        return query_min(chr,mid+1,r,ll,rr);
    else return min(query_min(chl,l,mid,ll,mid),query_min(chr,mid+1,r,mid+1,rr));
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        tmp[i]=a[i];
        scanf("%d",&b[i]);
    }
    sort(tmp+1,tmp+n+1);
    for(int i=1;i<=n;i++){
        int pos=lower_bound(tmp+1,tmp+n+1,a[i])-tmp;
        lis[i]=pos;
        num[pos]=b[i];
    }
    build_tree(1,1,n);
    for(int i=1;i<=n;i++){
        int val=num[lis[i]];
        int pos;
        if(lis[i]>1&&(pos=query_max(1,1,n,1,lis[i]-1,val)))
            change(1,1,n,pos,val);
        if(lis[i]<n&&(!query_max(1,1,n,lis[i]+1,n,val))){
            PII ans=query_min(1,1,n,lis[i]+1,n);
            pos=ans.second;
            change(1,1,n,pos,val);
        }
    }
    for(int i=1;i<=n;i++)
        printf("%d%c",num[lis[i]],i==n?'\n':' ');
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值