洛谷 P1725 琪露诺(线段树优化dp)

题目链接

https://www.luogu.com.cn/problem/P1725

思路

我们令 d p [ i ] dp[i] dp[i]表示琪露诺移动到第 i i i个格子时能够获得的最大冰冻指数。

显然,状态转移方程为: d p [ i ] = m a x ( d p [ i ] , d p [ k ] + a [ i ] ) dp[i] = max(dp[i],dp[k]+a[i]) dp[i]=max(dp[i],dp[k]+a[i]),其中 k + L ≤ i k+L \le i k+L≤i并且 ( k + R ≥ i ) (k+R \ge i) (k+R≥i)。

因为 L L L和 R R R的值很大,所以我们可以使用线段树来进行优化。

使用线段树维护区间 d p [ i ] dp[i] dp[i]的最大值,每计算出一个新的 d p [ i ] dp[i] dp[i],就将其扔到线段树中。我们令编号从 1 1 1开头,则最后的答案为 d p [ n + 2 ] dp[n+2] dp[n+2]。

代码

cpp 复制代码
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double

typedef long long i64;
typedef unsigned long long u64;
typedef pair<int, int> pii;

const int N = 2e5 + 5, M = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;

int n, l, r;
int a[N], dp[N];
struct segmenttree
{
    struct node
    {
        int l, r, maxx, tag;
    };

    vector<node>tree;

    segmenttree(): tree(1) {}
    segmenttree(int n): tree(n * 4 + 1) {}

    void pushup(int u)
    {
        auto &root = tree[u], &left = tree[u << 1], &right = tree[u << 1 | 1];
        root.maxx = max(left.maxx, right.maxx);
    }

    void pushdown(int u)
    {
        auto &root = tree[u], &left = tree[u << 1], &right = tree[u << 1 | 1];
        if (root.tag)
        {
            left.tag = root.tag;
            right.tag = root.tag;
            left.maxx = root.tag;
            right.maxx = root.tag;
            root.tag = 0;
        }
    }

    void build(int u, int l, int r)
    {
        auto &root = tree[u];
        root = {l, r};
        if (l == r)
        {
            root.maxx = -inf;
            return;
        }
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }

    void modify(int u, int l, int r, int val)
    {
        auto &root = tree[u];
        if (root.l >= l && root.r <= r)
        {
            root.maxx = val;
            root.tag = val;
            return;
        }
        pushdown(u);
        int mid = root.l + root.r >> 1;
        if (l <= mid) modify(u << 1, l, r, val);
        if (r > mid) modify(u << 1 | 1, l, r, val);
        pushup(u);
    }

    int query(int u, int l, int r)
    {
        auto &root = tree[u];
        if (root.l >= l && root.r <= r)
        {
            return root.maxx;
        }
        pushdown(u);
        int mid = root.l + root.r >> 1;
        int res = -inf;
        if (l <= mid) res = query(u << 1, l, r);
        if (r > mid) res = max(res, query(u << 1 | 1, l, r));

        return res;
    }
};
void solve()
{
    cin >> n >> l >> r;
    fill(dp, dp + 1 + n + 2, -inf);
    for (int i = 1; i <= n + 1; i++)
    {
        cin >> a[i];
    }
    segmenttree smt(n + 1);
    smt.build(1, 1, n + 1);
    dp[1] = a[1];
    smt.modify(1, 1, 1, dp[1]);
    for (int i = 2; i <= n + 1; i++)
    {
        if (i - l < 1)
        {
            dp[i] = -inf;
            continue;
        }
        dp[i] = max(dp[i], smt.query(1, max(i - r, 1ll), max(i - l, 1ll)) + a[i]);
        smt.modify(1, i, i, dp[i]);
    }
    //n+2表示对岸,包括>n+1的所有格子,所以要特殊处理。
    dp[n + 2] = smt.query(1, max(n + 2 - r, 1ll), max(n + 2 - 1, 1ll));
    cout << dp[n + 2] << endl;
}

signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int test = 1;
    // cin >> test;
    for (int i = 1; i <= test; i++)
    {
        solve();
    }
    return 0;
}
相关推荐
搬砖的小码农_Sky1 小时前
C语言:数组
c语言·数据结构
Swift社区2 小时前
LeetCode - #139 单词拆分
算法·leetcode·职场和发展
Kent_J_Truman2 小时前
greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用
算法
先鱼鲨生3 小时前
数据结构——栈、队列
数据结构
一念之坤3 小时前
零基础学Python之数据结构 -- 01篇
数据结构·python
IT 青年3 小时前
数据结构 (1)基本概念和术语
数据结构·算法
熬夜学编程的小王3 小时前
【初阶数据结构篇】双向链表的实现(赋源码)
数据结构·c++·链表·双向链表
Dong雨3 小时前
力扣hot100-->栈/单调栈
算法·leetcode·职场和发展
SoraLuna3 小时前
「Mac玩转仓颉内测版24」基础篇4 - 浮点类型详解
开发语言·算法·macos·cangjie
liujjjiyun4 小时前
小R的随机播放顺序
数据结构·c++·算法