2019年牛客多校第一场 I题Points Division 线段树+DP

题目链接

传送门

题意

给你 n n n个点,每个点的坐标为 ( x i , y i ) (x_i,y_i) (xi,yi),有两个权值 a i , b i a_i,b_i ai,bi
现在要你将它分成 A , B \mathbb{A},\mathbb{B} A,B两部分,使得在满足“ A \mathbb{A} A的点不能落在在 B \mathbb{B} B的点的右下方”的条件下 ∑ i ∈ A a i + ∑ j ∈ B b j \sum\limits_{i\in\mathbb{A}}a_i+\sum\limits_{j\in\mathbb{B}}b_j iAai+jBbj最大。

思路

这篇博客讲得很详细,大家可以看这位大佬的昂~

代码实现如下

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<
#define FIN freopen("D://Code//in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 1000000007;
const int maxn = 1e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int n;
vector<int> vec;
struct Point {
    int x, y, a, b;
    bool operator < (const Point& pp) const {
        return x == pp.x ? y > pp.y : x < pp.x;
    }
}point[maxn];

struct node {
    int l, r;
    LL mx, lazy;
}segtree[maxn<<2];

void push_up(int rt) {
    segtree[rt].mx = max(segtree[lson].mx, segtree[rson].mx);
}

void push_down(int rt) {
    LL x = segtree[rt].lazy;
    segtree[rt].lazy = 0;
    segtree[lson].lazy += x;
    segtree[rson].lazy += x;
    segtree[lson].mx += x;
    segtree[rson].mx += x;
}

void build(int rt, int l, int r) {
    segtree[rt].l = l, segtree[rt].r = r;
    segtree[rt].mx = segtree[rt].lazy = 0;
    if(l == r) return;
    int mid = (segtree[rt].l + segtree[rt].r) >> 1;
    build(lson, l, mid);
    build(rson, mid + 1, r);
}

void update1(int rt, int pos, LL val) {
    if(segtree[rt].l == segtree[rt].r) {
        segtree[rt].mx = val;
        return;
    }
    push_down(rt);
    int mid = (segtree[rt].l + segtree[rt].r) >> 1;
    if(pos <= mid) update1(lson, pos, val);
    else update1(rson, pos, val);
    push_up(rt);
}

void update2(int rt, int l, int r, LL val) {
    if(segtree[rt].l == l && segtree[rt].r == r) {
        segtree[rt].mx += val;
        segtree[rt].lazy += val;
        return;
    }
    push_down(rt);
    int mid = (segtree[rt].l + segtree[rt].r) >> 1;
    if(r <= mid) update2(lson, l, r, val);
    else if(l > mid) update2(rson, l, r, val);
    else {
        update2(lson, l, mid, val);
        update2(rson, mid + 1, r, val);
    }
    push_up(rt);
}

LL query(int rt, int l, int r) {
    if(segtree[rt].l == l && segtree[rt].r == r) {
        return segtree[rt].mx;
    }
    push_down(rt);
    int mid = (segtree[rt].l + segtree[rt].r) >> 1;
    if(r <= mid) return query(lson, l, r);
    else if(l > mid) return query(rson, l, r);
    else return max(query(lson, l, mid), query(rson, mid + 1, r));
}

int main() {
#ifndef ONLINE_JUDGE
FIN;
#endif // ONLINE_JUDGE
    while(~scanf("%d", &n)) {
        vec.clear();
        for(int i = 1; i <= n; ++i) {
            scanf("%d%d%d%d", &point[i].x, &point[i].y, &point[i].a, &point[i].b);
            vec.push_back(point[i].y);
        }
        sort(vec.begin(), vec.end());
        vec.erase(unique(vec.begin(), vec.end()), vec.end());
        sort(point + 1, point + n + 1);
        for(int i = 1; i <= n; ++i) {
            point[i].y = lower_bound(vec.begin(), vec.end(), point[i].y) - vec.begin() + 1;
        }
        int sz = vec.size();
        build(1, 0, sz + 1);
        for(int i = 1; i <= n; ++i) {
            LL num = query(1, 0, point[i].y);
            update1(1, point[i].y, num + point[i].b);
            update2(1, 0, point[i].y - 1, point[i].a);
            update2(1, point[i].y + 1, sz + 1, point[i].b);
        }
        printf("%lld\n", segtree[1].mx);
    }
    return 0;
}

你可能感兴趣的:(迷之dp,比赛题解,谜之线段树)