HUST1349 Signal Beacon【单调栈+线段树DP】

31 篇文章 0 订阅
14 篇文章 0 订阅

题意:

n 座山,每座山有一个高度 Hi,在每座山上安放一个信号塔需要花费 Ci ,每座山上的信号塔的信号能传到向左/右离这座塔最近的比他高的山。

思路

先预处理对每座山的信号塔向左和向右最远的位置 [Left,Right] ,这里利用单调栈就可以了。
将每个区间按照左端点从小到大排序,左端点相等的话,按照右端点从小到大排序。
dp[i] 代表从位置 1 到位置 i 的最小花费。
对于区间 [Left,Right] ,我们只需要维护从位置 1 Right 的最小花费: dp[Right]=min{dp[i],i[Left,Right1]}+C[Left,Right] ;
要区间求最小值可以用线段树维护,那么就是线段树维护 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值