P2486 拦截导弹 题解

首先相比传统的拦截导弹问题,这道题目多了一维速度,所以说 dp 方程可以变成。

\(dp_i=1+\max_jdp_j[a_j>a_i][b_j>b_i][j<i]\)

我们还想求出最大方案的数量。那么我们再维护一个数量,好像就可以了,然后跑两次 cdq,先求出每个点的 dp 值,然后再跑一次 cdq 求数量?数量的 dp 式子可以是

\(f_i=\sum_jf_j[a_j>a_i][b_j>b_i][j<i][dp_j=dp_i-1]\)

其实已经可以能弄,但是感觉不是很优,再想想。

dp 值其实就是右上角里面找一个 dp 最大的点,f 值呢?右上角所有 dp 最大的点的 f 的和。这东西怎么优化?

看了一下题解,这个东西很容易就维护了,树状数组的每个点搞两维,最大值被更新了就更新 cnt。

而且还有一个问题我没有考虑到,就是要反着做一次,因为一个点前面的路径数量还要乘以后面的路径数量。还是比较自然的。

#include<bits/stdc++.h>
#define rep(I, J, K) for(int I = (int)J; I <= (int)K; ++I)
#define per(I, J, K) for(int I = (int)J; I >= (int)K; --I)
using namespace std;
const int N = 5e5 + 10;

typedef long long ll;
struct Point {
    int x, y, z;
    bool operator < (const Point &point) const {
        return (y == point.y) ? z < point.z : y > point.y;
    }
}p[N];

struct Node {
    int dp;
    double cnt;
    Node operator + (const Node &node) const {
        if(dp < node.dp) return node;
        if(dp > node.dp) return {dp, cnt};
        return {dp, cnt + node.cnt};
    }
};
struct Fenwick_Tree {
    Node val[N];
    const int MAXN = 5e4 + 10;
    int lowbit(int x) { return x & -x; }
    void insert(int p, Node x) {
        // cerr << p << '\n';
        while(p <= MAXN) {
            val[p] = val[p] + x;
            p += lowbit(p);
        }
    }
    void Clear(int p) {
        while(p <= MAXN) {
            val[p] = {0, 0};
            p += lowbit(p);
        }
    } 
    Node Query(int p) {
        Node res = {-1, 1};
        // cerr << p << '\n';
        while(p) {
            res = res + val[p];
            p -= lowbit(p);
        }
        return res;
    }
}bit;

int n, a[N], b[N], c[N];
Node dp1[N], dp2[N];

void solve(int l, int r) {
    if(l == r) {
        dp1[p[l].x] = dp1[p[l].x] + (Node){1, 1};
        return;
    }
    int mid = l + r >> 1;
    solve(l, mid);
    vector<Point>left(p + l, p + mid + 1), right(p + mid + 1, p + r + 1);
    sort(left.begin(), left.end()); sort(right.begin(), right.end());
    int i = 0;
    rep(j, 0, right.size() - 1) {
        while(i < left.size() && left[i].y >= right[j].y) bit.insert(left[i].z, dp1[left[i].x]), ++i;
        Node tmp = bit.Query(right[j].z); tmp.dp += 1;
        dp1[right[j].x] = dp1[right[j].x] + tmp;
        // cerr << j << ' ' << i << ' ' << p[j].x << ' ' << dp1[p[j].x].dp << ' ' << dp1[p[j].x].cnt << '\n';
    }
    rep(j, 0, i - 1) bit.Clear(left[j].z);
    solve(mid + 1, r);
}
void solve2(int l, int r) {
    if(l == r) {
        dp2[p[l].x] = dp2[p[l].x] + (Node){1, 1};
        return;
    }
    int mid = l + r >> 1;
    solve2(mid + 1, r);
    vector<Point>left(p + l, p + mid + 1), right(p + mid + 1, p + r + 1);
    sort(left.begin(), left.end()); sort(right.begin(), right.end());
    int j = right.size() - 1;
    per(i, left.size() - 1, 0) {
        while(j >= 0 && right[j].y <= left[i].y) bit.insert(right[j].z, dp2[right[j].x]), --j;
        Node tmp = bit.Query(left[i].z); tmp.dp++;
        dp2[left[i].x] = dp2[left[i].x] + tmp;
    }
    per(i, right.size() - 1, j + 1) bit.Clear(right[i].z);
    solve2(l, mid);
}

int main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    cin >> n;
    rep(i, 1, n) cin >> a[i] >> b[i], c[i] = b[i];
    sort(c + 1, c + n + 1);
    int m = unique(c + 1, c + n + 1) - c - 1;
    rep(i, 1, n) b[i] = lower_bound(c + 1, c + m + 1, b[i]) - c;
    // cerr << m << '\n';
    // rep(i, 1, n) cerr << b[i] << ' ';
    // cerr << '\n';
    rep(i, 1, n) p[i] = {i, a[i], m - b[i] + 1};
    // rep(i, 1, n) cerr << p[i].z << ' ';
    // cerr << '\n';
    solve(1, n);
    Node ans = {0, 0};
    rep(i, 1, n) ans = ans + dp1[i];
    cout << ans.dp << '\n';
    rep(i, 1, n) p[i] = {i, a[i], b[i]};
    solve2(1, n);
    // rep(i, 1, n) cerr << dp2[i].dp << ' ' << dp2[i].cnt << '\n';
    assert(ans.cnt != 0);
    rep(i, 1, n) {
        if(dp1[i].dp + dp2[i].dp - 1 == ans.dp) {
            // cout << dp2[i].cnt << endl;
            cout << fixed << setprecision(10) << (double)dp1[i].cnt * dp2[i].cnt / ans.cnt << ' ';
        } else {
            cout << 0 << ' ';
        }
    }
    cout << '\n';
    return 0;
}
posted @ 2026-09-10 09:50  Mercury_City  阅读(5)  评论(0)    收藏  举报