• [Codeforces 115E]Linear Kingdom Races


    题目大意:

    有n块地,初始是荒地。你可以把某些荒地开垦(需要花费相应的价值(a_i)(正整数)),然后这些荒地就可以种田。

    现在有m年,每年要在l到r区间内种田,获得p(正整数)的价值(必须保证l~r都已经开荒,否则不能种田)。

    问最大收益。

    解题思路:

    DP。

    设F[i][j]表示前i块地,最后有连续的j块地已开荒的最大收益。

    则(F[i+1][0]=max{F[i][j]})。不开荒,则中间断了,所以连续的值只有0了。

    F[i+1][j+1]=F[i][j]-a[i]+v。开荒,则花费价值,而且可能会有一些年份可以种田了,则加上这些收益(v是加上后能多出来的种田收益)。

    于是我们要记录下以每个值作为右端点的种田个数。

    答案即为(max{F[n][i]})

    发现这是个时空复杂度都是(O(n^2))的东西。

    首先第一维可以滚掉。

    然后,考虑每个(a[i])都要在整个区间减一遍,而每年种田的价值也会对一段区间有影响。

    所以考虑线段树优化。

    线段树每个节点记录这个节点下面的儿子的状态的最优值。

    然后发现枚举i时,之前的状态都要向右偏移一格,非常麻烦。

    倒着建状态就好辣~喵~o( =∩ω∩= )m

    C++ Code:

    #include<bits/stdc++.h>
    using namespace std;
    using LoveLive=long long;
    const int N=2e5+5;
    LoveLive d[N*4],tag[N*4],a[N];
    int n,m,L,R;
    LoveLive add;
    vector<pair<int,LoveLive>>v[N];
    inline LoveLive max(LoveLive&a,LoveLive&b){return a>b?a:b;}
    inline void pd(int&o){
        if(tag[o]){
            int l=o<<1,r=l|1;
            d[l]+=tag[o];
            d[r]+=tag[o];
            tag[l]+=tag[o];
            tag[r]+=tag[o];
            tag[o]=0;
        }
    }
    void add_1(int l,int r,int o){
        if(l==r)d[o]+=add;else{
            pd(o);
            int mid=l+r>>1;
            if(L<=mid)add_1(l,mid,o<<1);else
            add_1(mid+1,r,o<<1|1);
            d[o]=max(d[o<<1],d[o<<1|1]);
        }
    }
    void add_lot(int l,int r,int o){
        if(L<=l&&r<=R)d[o]+=add,tag[o]+=add;else{
            int mid=l+r>>1;
            pd(o);
            if(L<=mid)add_lot(l,mid,o<<1);
            if(mid<R)add_lot(mid+1,r,o<<1|1);
            d[o]=max(d[o<<1],d[o<<1|1]);
        }
    }
    int main(){
        ios::sync_with_stdio(0),cin.tie(0);
        cin>>n>>m;
        for(int i=1;i<=n;++i)cin>>a[i];
        for(int i=1,l,r;i<=m;++i){
            cin>>l>>r>>add;
            v[r].push_back(make_pair(l,add));
        }
        for(int i=1;i<=n;++i){
            L=n-i,add=d[1];
            add_1(0,n,1);
            ++L,R=n,add=-a[i];
            add_lot(0,n,1);
            for(auto it:v[i]){
                L=n-it.first+1,R=n,add=it.second;
                add_lot(0,n,1);
            }
        }
        cout<<d[1]<<endl;
        return 0;
    }
  • 相关阅读:
    [leetCode]404. 左叶子之和
    [leetCode]572. 另一个树的子树
    [leetCode]226. 翻转二叉树
    [leetCode]637. 二叉树的层平均值
    [leetCode]102. 二叉树的层序遍历
    [leetCode]590. N叉树的后序遍历
    [leetCode]589. N叉树的前序遍历
    [leetCode]145. 二叉树的后序遍历
    [leetCode]94. 二叉树的中序遍历
    [leetCode]381. O(1) 时间插入、删除和获取随机元素
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9385612.html
Copyright © 2020-2023  润新知