链接: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)
n(n≤2×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)
h(10−9≤x≤109,1≤h≤109)(保证每个 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;
}