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
  • 相关阅读:
    gitment Error:validation failed错误解决办法
    Hexo博客yilia主题添加Gitment评论系统
    用DateTime的ParseExact方法解析特殊的日期时间
    C#中的日期处理函数
    SQL,Linq,Lambda之间的转换练习
    Windows Azure Platform 系列文章目录
    Linq查询表达式
    EF框架的三种工作方式
    jQuery UI 实现图片循环显示,常用于网站首页banner广告切换
    jQuery UI Datepicker
  • 原文地址:https://www.cnblogs.com/AaronChang/p/12437078.html
Copyright © 2011-2022 走看看