题意:
有
n
座山,每座山有一个高度
思路
先预处理对每座山的信号塔向左和向右最远的位置
[Left,Right]
,这里利用单调栈就可以了。
将每个区间按照左端点从小到大排序,左端点相等的话,按照右端点从小到大排序。
dp[i]
代表从位置
1
到位置
对于区间
[Left,Right]
,我们只需要维护从位置
1
到
要区间求最小值可以用线段树维护,那么就是线段树维护
dp[i]
, 就完了~
哇!
Makedown is excellent!
//#include <bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<math.h>
#include<algorithm>
typedef long long LL;
using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000")
const LL INF=1e18;
const int N=1e4+10;
int n,cost[N],h[N];
struct asd
{
int Left,Right;
int id,w;
} w[N];
bool cmp(asd x,asd y)
{
if(x.Left == y.Left) return x.Right<y.Right;
return x.Left<y.Left;
}
stack<asd>q;
void init()
{
asd now,nex;
while(!q.empty())
q.pop();
now.Left=1;
now.Right=1;
now.w=h[1];
now.id=1;
q.push(now);
for(int i=2; i<=n; i++)
{
now.id=i;
now.Left=i;
now.Right=i;
now.w=h[i];
while(!q.empty()&&q.top().w<h[i])
{
nex=q.top();
q.pop();
w[nex.id].id=nex.id;
w[nex.id].Left=nex.Left;
if(nex.Left-1>=1&&h[nex.Left-1]>h[nex.id]) w[nex.id].Left--;
w[nex.id].Right=nex.Right;
if(nex.Right+1<=n&&h[nex.Right+1]>h[nex.id]) w[nex.id].Right++;
now.Left=nex.Left;
if(!q.empty())
q.top().Right=nex.Right;
}
q.push(now);
}
while(!q.empty())
{
nex=q.top();
q.pop();
w[nex.id].id=nex.id;
w[nex.id].Left=nex.Left;
if(nex.Left-1>=1&&h[nex.Left-1]>h[nex.id]) w[nex.id].Left--;
w[nex.id].Right=nex.Right;
if(nex.Right+1<=n&&h[nex.Right+1]>h[nex.id]) w[nex.id].Right++;
if(!q.empty())
q.top().Right=nex.Right;
}
// for(int i=1; i<=n; i++)
// printf("%d %d\n",w[i].Left,w[i].Right);
}
struct Seg{
int Left,Right;
LL sum;
}qt[N*4];
void Build(int num,int Left,int Right){
qt[num].sum=INF;
qt[num].Left=Left;
qt[num].Right=Right;
if(Left == Right) return;
int Mid=(Left+Right)>>1;
Build(num<<1,Left,Mid);
Build(num<<1|1,Mid+1,Right);
}
LL query(int num,int s,int t){
if(qt[num].Left>=s && qt[num].Right<=t)
return qt[num].sum;
int Mid=(qt[num].Left + qt[num].Right)>>1;
if(Mid >= t)
return query(num<<1,s,t);
else if(Mid < s)
return query(num<<1|1,s,t);
else
return min(query(num<<1,s,Mid),query(num<<1|1,Mid+1,t));
}
void Update(int num,int pos,LL val){
if(qt[num].Left == qt[num].Right){
if(qt[num].Left == pos)
qt[num].sum=min(qt[num].sum,val);
return;
}
int Mid=(qt[num].Left+qt[num].Right)>>1;
if(Mid >= pos) Update(num<<1,pos,val);
else Update(num<<1|1,pos,val);
qt[num].sum=min(qt[num<<1].sum,qt[num<<1|1].sum);
}
void solve(){
Build(1,1,n);
sort(w+1,w+n+1,cmp);
LL temp;
Update(1,w[1].Right,cost[w[1].id]);
for(int i=2;i<=n;i++)
{
temp = 0;
if(w[i].Left != 1)
temp = query(1,w[i].Left,w[i].Right-1);
temp = temp + cost[w[i].id];
Update(1,w[i].Right,temp);
}
printf("%lld\n",query(1,n,n));
}
int main()
{
int cas=1;
while(~scanf("%d",&n))
{
for(int i=1; i<=n; i++)
scanf("%d",&h[i]);
for(int i=1; i<=n; i++)
scanf("%d",&cost[i]);
init();
printf("Case #%d: ",cas++);
solve();
}
return 0;
}