zoukankan      html  css  js  c++  java
  • 牛客 Neat Tree (单调栈)

    https://ac.nowcoder.com/acm/problem/15815

    首先暴力枚举每一个区间必定是超时的。那么考虑每个点对于答案的贡献值,可以这样想,对于点h[i]作为最大值在多少个区间出现,作为最小值在多少个区间出现?这个点对于答案的贡献就是h[i]*作为最大值出现的次数 - h[i]*作为最小值出现的次数,对于每个点,求一下贡献累加即可。

    求每个点贡献的过程用单调栈来维护,拿求最大值的次数来举例。对于点i,找到左端第一个比h[i]大的数,记其位置为L,找到右端第一个比h[i]大的数,记其位置为R,则在(L,R)区间内包含点[i]的子区间个数就是 (i-L+1)*(R-i+1),可以画图理解一下。那么对于答案的贡献就是h[i]*(i-L+1)*(R-i+1)。

    同理求出最小值的贡献,减去这个贡献,最终得到答案

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn = 1e6+5;
     5 int h[maxn],l[maxn],r[maxn],n;
     6 void solve(){
     7     ll sum = 0;
     8     stack<int> stk;
     9     for(int i = 1;i<=n;i++) cin>>h[i];
    10     //先求h[i]作为一段区间的最小值出现的次数
    11     for(int i = 1;i<=n;i++) {
    12         while(!stk.empty() && h[stk.top()]>=h[i]) stk.pop();
    13         if(stk.empty()) l[i] = 1;
    14         else l[i] = stk.top() + 1;//记录h[i]左端第一个比h[i]小的index;
    15         stk.push(i);//压入栈中
    16     }
    17     while(!stk.empty()) stk.pop();
    18     for(int i = n;i>=1;i--){
    19         while(!stk.empty() && h[stk.top()]>h[i]) stk.pop();
    20         if(stk.empty()) r[i] = n;
    21         else r[i] = stk.top()-1;//记录h[i]右端第一个比h[i]小的index;
    22         stk.push(i);
    23     }
    24     while(!stk.empty()) stk.pop();
    25     //
    26     for(int i = 1;i<=n;i++) sum-=1ll*h[i]*(i-l[i]+1)*(r[i]-i+1);
    27     //再求h[i]作为一段区间的最小值出现的次数
    28     for(int i = 1;i<=n;i++){
    29         while(!stk.empty() && h[stk.top()]<=h[i]) stk.pop();
    30         if(stk.empty()) l[i] = 1;
    31         else l[i] = stk.top() + 1;//记录h[i]左端第一个比h[i]大的数的index;
    32         stk.push(i);
    33     }
    34     while(!stk.empty()) stk.pop();
    35     for(int i = n;i>=1;i--){
    36         while(!stk.empty() && h[stk.top()]<h[i]) stk.pop();
    37         if(stk.empty()) r[i] = n;
    38         else r[i] = stk.top()-1;//记录h[i]右端第一个比h[i]大的数的index;
    39         stk.push(i);
    40     }
    41     for(int i = 1;i<=n;i++) sum+=1ll*h[i]*(i-l[i]+1)*(r[i]-i+1);
    42     cout<<sum<<endl;
    43 }
    44 int main(){
    45     while(cin>>n){
    46         solve();
    47     }
    48     return 0;
    49 }
    View Code
  • 相关阅读:
    认识弹性盒子
    管理Linux服务器的用户和组(续篇)
    管理Linux服务器的用户和组
    centos7 mysql数据库安装和配置
    熟练使用Linux进程管理类命令
    熟练使用Linux系统信息类命令
    Linux操作系统-基本命令(二)
    Linux操作系统-基本命令(一)
    api接口统一封装
    10分钟,让你彻底明白Promise原理
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12437078.html
Copyright © 2011-2022 走看看