2478 小b接水
- 2 秒
- 262,144 KB
- 20 分
- 3 级题
小b将n个宽度相同的积木顺序摆在一起,如下图所示。
现在她告诉你每个积木的高度(可能为0)。
她想知道如果她从高处倒下一杯水,最多有多少单位的水能被积木接住?
假设每个积木的宽度都为1。
上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,最多可以接 6 个单位的水(蓝色部分表示水)。
收起
输入
第一行一个正整数n,其中0<n≤50000; 第二行n个数表示从左到右每个积木的高度,以空格隔开,每个数不超过10000。
输出
一个数,表示最多可以接的水量
输入样例
12 0 1 0 2 1 0 1 3 2 1 2 1
输出样例
6
题解:分类讨论: 1> 右边存在比当前值大的 2 1 3
2> 右边不存在比当前值大的 5 1 2 3 1 3 1 2
5 1 2 3 1 3 算一个区间
3 1 2 算一个区间
很显然,第一种用单调栈就行;第二种用map记录一下右边第一次出现某个值的位置(移动时用),用线段树求出当前值 右边最大值,显然,这么组合是最优的。
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<bitset>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define eps (1e-8)
#define MAX 0x3f3f3f3f
#define u_max 1844674407370955161
#define l_max 9223372036854775807
#define i_max 2147483647
#define re register
#define pushup() tree[rt]=max(tree[rt<<1],tree[rt<<1|1])
#define nth(k,n) nth_element(a,a+k,a+n); // 将 第K大的放在k位
#define ko() for(int i=2;i<=n;i++) s=(s+k)%i // 约瑟夫
#define ok() v.erase(unique(v.begin(),v.end()),v.end()) // 排序,离散化
using namespace std;
inline int read(){
char c = getchar(); int x = 0, f = 1;
while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
while(c >= '0' & c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}
typedef long long ll;
const double pi = atan(1.)*4.;
const int M=1e3+5;
const int N=5e5+5;
int a[N],l[N],r[N],tree[N];
stack<int>s1,s2;
void sett(int l,int r,int rt){
if(l==r){
tree[rt]=a[l];
return ;
}
int mid=l+r>>1;
sett(l,mid,rt<<1);
sett(mid+1,r,rt<<1|1);
pushup();
}
int findd(int x,int y,int l,int r,int rt){
if(x<=l&&r<=y)
return tree[rt];
int mid=l+r>>1;
int ans=0;
if(x<=mid)
ans=max(ans,findd(x,y,l,mid,rt<<1));
if(y>mid)
ans=max(ans,findd(x,y,mid+1,r,rt<<1|1));
return ans;
}
map<int,int>mapp;
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sett(1,n,1);
for(int i=1;i<=n;i++){
while(s1.size()&&a[s1.top()]<a[i]) s1.pop();
if(s1.empty()) l[i]=0;
else l[i]=s1.top();
s1.push(i);
}
for(int i=n;i>=1;i--){
while(s2.size()&&a[s2.top()]<a[i]) s2.pop();
if(s2.empty()) r[i]=n+1;
else r[i]=s2.top();
s2.push(i);
if(mapp.count(a[i])) continue;
mapp[a[i]]=i;
}
int p=1,ans=0;
while(p<n){
if(r[p]==n+1){
int d=findd(p+1,n,1,n,1);
int h=mapp[d];
for(int i=p+1;i<h;i++)
ans+=d-a[i];
p=h;
continue;
}
int d=a[p];
for(int i=p+1;i<r[p];i++)
ans+=d-a[i];
p=r[p];
}
printf("%d\n",ans);
return 0;
}