2019牛客暑期多校训练营(第一场场)_I题Points Division(线段树+DP维护区间最大值)

题目链接: https://ac.nowcoder.com/acm/contest/881/I

题意: 给你n个点,每个点的坐标为(xi,yi),有两个权值ai,bi。
现在要你将它分成A,B两部分,使得在满足“A的点不能落在在B的点的右下方”的条件下∑i∈Aai+∑j∈Bbj最大。

思路:可以参考一下大佬的博客

代码:

下午的时候,看了大佬写的博文,也按着他的思路自己敲了一遍,后面发现自己忘记开long long 就索性全文替换了,改完之后再交发现还是没过,emmmmmm(只通过0.01%的样例), 晚上突然一想到,我去,忘记初始化lazy了,哎…

#include <bits/stdc++.h>
using namespace std;
const long long MAXN = 1e5 + 5;
long long node[MAXN<<2], lazy[MAXN<<2];

inline void PushUp(long long root)
{
    node[root] = max(node[root<<1], node[root<<1|1]);
}

inline void BuildTree(long long root, long long l, long long r)
{
    if(l == r){
        node[root] = 0;
        return ;
    }
    //lazy 也要初始化,否则会有遗留
	lazy[root] = 0;

    long long mid = (l + r) >> 1;

    BuildTree(root<<1, l, mid);
    BuildTree(root<<1|1, mid + 1, r);

    PushUp(root);

}

inline void PushDown(long long root, long long ln, long long rn)
{

    if(lazy[root]){

        lazy[root<<1] += lazy[root];
        lazy[root<<1|1] += lazy[root];

        node[root<<1] += lazy[root];
        node[root<<1|1] += lazy[root];

        lazy[root] = 0;
    }

}

inline void Update(long long root, long long l, long long r, long long index, long long value)
{
    if(l == r){
        node[root] = value;
        return ;
    }
    long long mid = (l + r) >> 1;
    PushDown(root, mid - l + 1, r - mid);

    if(index <= mid)
        Update(root<<1, l, mid, index, value);
    else
        Update(root<<1|1, mid + 1, r, index, value);

    PushUp(root);
}

inline void Update(long long root, long long l, long long r, long long L, long long R, long long value)
{

    if(L <= l && r <= R){

        node[root] += value;
        lazy[root] += value;
        return ;
    }
    long long mid = (l + r) >> 1;

    PushDown(root, mid - l + 1, r - mid);
    if(L <= mid)
        Update(root<<1, l, mid, L, R, value);
    if(R > mid)
        Update(root<<1|1, mid + 1, r, L, R, value);

    PushUp(root);
}

inline long long Query(long long root, long long l, long long r, long long L, long long R)
{

    if(L <= l && r <= R){

        return node[root];
    }
    long long mid = (l + r) >> 1;

    PushDown(root, mid - l + 1, r - mid);

    long long ans = 0;
    if(L <= mid)
        ans = max(ans, Query(root<<1, l, mid, L, R));
    if(R > mid)
        ans = max(Query(root<<1|1, mid + 1, r, L, R), ans);

    return ans;
}
//
struct p
{
    long long x;
    long long y;
    long long a;
    long long b;

    friend bool operator <(const p as, p bs)
    {
        return (as.x == bs.x) ? as.y > bs.y : as.x < bs.x;
    }
};
/*
long long cmp(p as, p bs)
{
    return (as.x == bs.x) ? as.y > bs.y : as.x < bs.x;
}
*/
int main()
{
    ios::sync_with_stdio(false);
    long long n;
    while(cin >> n){
        vector<p> nodeVe;
        vector<long long> nVe;
        long long x, y, a, b;
        for(long long i = 1; i <= n; i++){
            cin >> x >> y >> a >> b;
            nodeVe.push_back(p{x, y, a, b});
            nVe.push_back(y);           //存在y, 后面对其进行离散化
        }
        sort(nVe.begin(), nVe.end());
        nVe.erase(unique(nVe.begin(), nVe.end()), nVe.end());
        //对Y进行离散化
        for(long long i = 0; i < n; i++){
            nodeVe[i].y = lower_bound(nVe.begin(), nVe.end(), nodeVe[i].y) - nVe.begin() + 1;
        }

        //sort(nodeVe.begin(), nodeVe.end(), cmp);
        sort(nodeVe.begin(), nodeVe.end());

        //建树,并初始化0,
        long long nTreeSize = nVe.size();
        BuildTree(1, 0, nTreeSize);     // 因为我们是y来进行dp, 所以树的大小就是nVe.size();

        //维护区间最值
        for(long long i = 0; i < n; i++){
            //修改这个点贡献即 dp[i]
            Update(1, 0, nTreeSize, nodeVe[i].y, Query(1, 0, nTreeSize, 0, nodeVe[i].y) + nodeVe[i].b);
            //更新左子树,右子树
            if(nodeVe[i].y - 1 >= 0) Update(1, 0, nTreeSize, 0, nodeVe[i].y - 1, nodeVe[i].a);
            if(nodeVe[i].y + 1 <= nTreeSize) Update(1, 0, nTreeSize, nodeVe[i].y + 1, nTreeSize, nodeVe[i].b);
        }
        cout << node[1] << endl;
    }

    return 0;
}


注释我按着自己的理解写的,如有误,可以指出,谢谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值