洛谷P2487 [SDOI2011] 拦截导弹 题解 CDQ分治优化DP

题目链接:https://www.luogu.com.cn/problem/P2487

解题思路完全来自:

其中最主要的是 hsfzLZH1 大佬 题解中的这段表述:

这个数据结构(线段树/树状数组)需要进行两种操作:

  1. 修改单点的值;
  2. 查询区间的最大值和对应的数值。

实现时,我是用了线段树。

  • \(j \lt i\)
  • \(h_j \ge h_i\)
  • \(v_j \ge v_i\)

\(f1_i\) 是所有满足上述条件的 \(j\) 对应的 \(\max\limits_{j} f1_j + 1\)

\(g1_i\) 是所有满足上述条件且 \(f1_j + 1 = f_i\)\(g1_j\) 之和。

\(f2_i\)\(g2_i\) 也是类似的操作。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4 + 5;

struct Segtree {
    int maxf[maxn<<2];
    double sumg[maxn<<2];
    #define lson l, mid, u<<1
    #define rson mid+1, r, u<<1|1
    void push_up(int u) {
        int f1 = maxf[u<<1], f2 = maxf[u<<1|1];
        double g1 = sumg[u<<1], g2 = sumg[u<<1|1];
        if (f1 > f2)
            maxf[u] = f1, sumg[u] = g1;
        else if (f2 > f1)
            maxf[u] = f2, sumg[u] = g2;
        else
            maxf[u] = f1, sumg[u] = g1 + g2;
    }

    void clean(int l, int r, int u) {
        if (!maxf[u])
            return;
        maxf[u] = sumg[u] = 0;
        if (l == r)
            return;
        int mid = l + r >> 1;
        clean(lson);
        clean(rson);
    }

    void add(int v, int f, double g, int l, int r, int u) {
        if (l == r) {
            if (f > maxf[u]) {
                maxf[u] = f;
                sumg[u] = g;
            }
            else if (f == maxf[u]) {
                sumg[u] += g;
            }
            return;
        }
        int mid = l + r >> 1;
        if (v <= mid)
            add(v, f, g, lson);
        else
            add(v, f, g, rson);
        push_up(u);
    }

    pair<int, double> query(int L, int R, int l, int r, int u) {
        if (L <= l && r <= R)
            return { maxf[u], sumg[u] };
        int mf = 0;
        double sg = 0;
        int mid = l + r >> 1;
        if (L <= mid) {
            auto [f, g] = query(L, R, lson);
            if (f > mf)
                mf = f, sg = g;
            else if (f == mf)
                sg += g;
        }
        if (R > mid) {
            auto [f, g] = query(L, R, rson);
            if (f > mf)
                mf = f, sg = g;
            else if (f == mf)
                sg += g;
        }
        return { mf, sg };
    }

} segt;

struct Node {
    int id, h, v, f;
    double g;
} a[maxn], b[maxn];
int n, m;

void init() {
    vector<int> vec;
    for (int i = 1; i <= n; i++) vec.push_back(a[i].v);
    sort(vec.begin(), vec.end());
    vec.erase(unique(vec.begin(), vec.end()), vec.end());
    m = vec.size();
    for (int i = 1; i <= n; i++)
        a[i].v = lower_bound(vec.begin(), vec.end(), a[i].v) - vec.begin() + 1;
    copy(a+1, a+n+1, b+1);
}

void cdq1(int l, int r) {
    if (l >= r)
        return;
    int mid = l + r >> 1;

    cdq1(l, mid);

    segt.clean(1, m, 1);
    sort(a+l, a+mid+1, [](auto a, auto b) {
        return a.h > b.h;
      });
    sort(a+mid+1, a+r+1, [](auto a, auto b) {
        return a.h > b.h;
      });
    for (int i = mid+1, j = l; i <= r; i++) {
        for (; j <= mid && a[j].h >= a[i].h; j++) {
            segt.add(a[j].v, a[j].f, a[j].g, 1, m, 1);
        }
        auto [f, g] = segt.query(a[i].v, m, 1, m, 1);
        if (f + 1 > a[i].f)
            a[i].f = f + 1, a[i].g = g;
        else if (f + 1 == a[i].f)
            a[i].g += g;
    }

    sort(a+mid+1, a+r+1, [](auto a, auto b) {
        return a.id < b.id;
      });
    cdq1(mid+1, r);
}

void cdq2(int l, int r) {
    if (l >= r)
        return;
    int mid = l + r >> 1;

    cdq2(mid+1, r);

    segt.clean(1, m, 1);
    sort(b+l, b+mid+1, [](auto a, auto b) {
        return a.h < b.h;
      });
    sort(b+mid+1, b+r+1, [](auto a, auto b) {
        return a.h < b.h;
      });
    for (int i = l, j = mid+1; i <= mid; i++) {
        for (; j <= r && b[i].h >= b[j].h; j++) {
            segt.add(b[j].v, b[j].f, b[j].g, 1, m, 1);
        }
        auto [f, g] = segt.query(1, b[i].v, 1, m, 1);
        if (f + 1 > b[i].f)
            b[i].f = f + 1, b[i].g = g;
        else if (f + 1 == b[i].f)
            b[i].g += g;
    }

    sort(b+l, b+mid+1, [](auto a, auto b) {
        return a.id < b.id;
      });
    cdq2(l, mid);
}

int main() {
    scanf("%d", &n);
    for (int i = 1, h, v; i <= n; i++) {
        scanf("%d%d", &h, &v);
        a[i] = { i, h, v, 1, 1 };
    }
    init();
    cdq1(1, n);
    cdq2(1, n);
    sort(a+1, a+n+1, [](auto a, auto b) {
        return a.id < b.id;
      });
    sort(b+1, b+n+1, [](auto a, auto b) {
        return a.id < b.id;
      });
    int ans = 0;
    double tot = 0;
    for (int i = 1; i <= n; i++) {
        if (a[i].f > ans)
            ans = a[i].f, tot = a[i].g;
        else if (a[i].f == ans)
            tot += a[i].g;
    }
    printf("%d\n", ans);
    for (int i = 1; i <= n; i++) {
        double tmp;
        if (a[i].f + b[i].f - 1 == ans)
            tmp = a[i].g * b[i].g / tot;
        else
            tmp = 0;
        printf("%lf ", tmp);
    }

    return 0;
}
posted @ 2026-01-16 03:50  quanjun  阅读(4)  评论(0)    收藏  举报