赛后补题——gk的爬山之旅

gk的爬山之旅

https://ac.nowcoder.com/acm/contest/30825/D

我们可以发现,每一步的最优解就是选择这座山右边第一高的或者左边第一高的,所以很明显,要用单调栈来进行一个维护。

//还差一个条件的实现,就是从右开始向后扫,找最右边第一个比堆顶大时
//碰见重复的连续串,应该选择第一个;找左边的则是找最后一个
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e6+7;
int g[M],h[M],l[M],r[M];
int f[M];
int t,n;
stack<int> q;
int jud(int a, int b){
    if(h[a]>h[b])
        return b;
    if(h[a]==h[b])
        return a;
    if(h[a]<h[b])
        return a;
    return 0;
}
int send(int x){
    if(f[x]!=0)
        return f[x];
    if(l[x]!=0) f[x] = max(f[x], send(l[x]) + abs(g[l[x]] - g[x]));
    if(r[x]!=n+1) f[x] = max(f[x], send(r[x]) + abs(g[r[x]] - g[x]));
    return f[x];//记忆化搜索(之前一直不会写,重点体会一下)
}
int main(){
    cin>>t;
    while(t--){
        cin>>n;
        
        for(int i=1; i<=n; i++)
            cin>>h[i];
        for(int i=1; i<=n; i++)
            cin>>g[i];
        
        h[0]=1e9+1,h[n+1]=0;
        q.push(n+1);
        for(int i=n; i>=0; i--){
            while(!q.empty()&&h[i]>h[q.top()]){
                l[q.top()]=i;
                q.pop();
            }
            q.push(i);
        }
        while(!q.empty())
            q.pop();//找每个的左边第一大
        
        h[0]=0,h[n+1]=1e9+1;
        q.push(0);
        for(int i=1; i<=n+1; i++){
            while(!q.empty()&&h[i]>h[q.top()]){//注意要把判断不为空的条件放前面
                r[q.top()]=i;
                q.pop();
            }
            //cout<<i<<" ";
            q.push(i);
        }
        while(!q.empty())
            q.pop();//找每个的右边第一大

        h[n+1]=1e9+1;
        for(int i=1; i<=n; i++){
            ll sum=0;
            int hj=i;
            sum=send(hj);
            cout<<sum<<" ";
        }
    }
    return 0;
}



全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务