拦截导弹

\[dp[i]=max(dp[j]+1),(h_j>h_i且v_j>v_i) \]

\(考虑用CDQ优化,为了保证在处理i之前,[1,i)已经被处理过,类似用中序遍历\)

\(对于右区间,暂时不处理,而(l,mid)处理(mid+1,r),更高一层的可以经过递归可以保证对\)

\(于每一个于右区间i,已经用[1,l]处理过\)

#include <bits/stdc++.h>
#define ls 2 * p
#define rs 2 * p + 1
using namespace std;
const int MAXN = 5e4 + 5;
int n;
struct Query {
    int pos, h, v;
    bool operator<(const Query x) const {
        if (h == x.h) {
            if (v == x.v) {
                return pos < x.pos;
            } else {
                return v > x.v;
            }
        } else {
            return h > x.h;
        }
        //		return h>x.h;
    }//顺序一定是h为第一关键字,v为第二关键字
	//对于pos,一定是小的更新大的 

} query[MAXN], tmp[MAXN];
struct Queryx {
    int pos, h, v;
    bool operator<(const Queryx x) const {
        if (h == x.h) {
            if (v == x.v) {
                return pos < x.pos;
            } else {
                return v < x.v;
            }
        } else {
            return h < x.h;
        }
        //		return h<x.h;
    }

} queryx[MAXN], tmpx[MAXN];//逆序的query 
int lsh[MAXN];
struct Segment {
    int l, r;
    int date;
    double num;
} Tree[MAXN * 4];
void push_up(int p) {
    Tree[p].date = max(Tree[ls].date, Tree[rs].date);
    Tree[p].num = 0;
    if (Tree[p].date == Tree[ls].date) {
        Tree[p].num += Tree[ls].num;
    }
    if (Tree[p].date == Tree[rs].date) {
        Tree[p].num += Tree[rs].num;
    }//统计max的方案 
}
void Build(int p, int l, int r) {
    Tree[p].l = l;
    Tree[p].r = r;
    if (l == r) {
        Tree[p].date = 0;
        Tree[p].num = 0;
        return;
    }
    int mid = (l + r) >> 1;
    Build(ls, l, mid);
    Build(rs, mid + 1, r);
    push_up(p);
}
int dp1[MAXN];
int dp2[MAXN];
double f1[MAXN];
double f2[MAXN];
void update(int p, int x, int k, double num) {
    if (Tree[p].l == Tree[p].r) {
        if (k > Tree[p].date) {
            Tree[p].date = k;
            Tree[p].num = num;
        } else if (Tree[p].date == k) {
            Tree[p].num += num;
        }//更新时统计方案数 
        return;
    }
    int mid = (Tree[p].l + Tree[p].r) >> 1;
    if (x <= mid) {
        update(ls, x, k, num);
    } else {
        update(rs, x, k, num);
    }
    push_up(p);
}
void clear(int p, int x) {//清空 
    if (Tree[p].l == Tree[p].r) {
        Tree[p].date = 0;
        Tree[p].num = 0;
        return;
    }
    int mid = (Tree[p].l + Tree[p].r) >> 1;
    if (x <= mid) {
        clear(ls, x);
    } else {
        clear(rs, x);
    }
    push_up(p);
}
pair<int, double> quest(int p, int l, int r) {
    if (Tree[p].l >= l && Tree[p].r <= r) {
        return make_pair(Tree[p].date, Tree[p].num);
    }
    int mid = (Tree[p].l + Tree[p].r) >> 1;
    if (l <= mid && r > mid) {
        pair<int, double> lp = quest(ls, l, r);
        pair<int, double> rp = quest(rs, l, r);
        int mad = max(lp.first, rp.first);
        double nop = 0;
        if (mad == lp.first) {
            nop += lp.second;
        }
        if (mad == rp.first) {
            nop += rp.second;
        }
        return make_pair(mad, nop);//左右儿子的方案数合并 
    } else if (l <= mid) {
        return quest(ls, l, r);
    } else if (r > mid) {
        return quest(rs, l, r);
    } else {
        return make_pair(1, 1.0);
    }
}
void solve(int l, int r) {
    if (l == r) {
        return;
    }
    int mid = (l + r) >> 1;
    solve(l, mid);
    int lpo = l;
    int rpo = mid + 1;
    for (int i = mid + 1; i <= r; i++) {
        tmp[i] = query[i];
    }//首先复制query,因为没有更新右区间,所以要用临时数组排序更新 
    sort(tmp + mid + 1, tmp + r + 1);
    while (lpo <= mid && rpo <= r) {
        if (query[lpo].h >= tmp[rpo].h) {//不上升 
            update(1, query[lpo].v, dp1[query[lpo].pos], f1[query[lpo].pos]);
            lpo++;
        } else {
            pair<int, double> rpl = quest(1, tmp[rpo].v, n);//后缀最大 
            if (rpl.first + 1 > dp1[tmp[rpo].pos]) {
                dp1[tmp[rpo].pos] = rpl.first + 1;
                f1[tmp[rpo].pos] = rpl.second;
            } else if (rpl.first + 1 == dp1[tmp[rpo].pos]) {
                f1[tmp[rpo].pos] += rpl.second;
            }//更新答案 
            rpo++;
        }
    }
    while (lpo <= mid) {
        update(1, query[lpo].v, dp1[query[lpo].pos], f1[query[lpo].pos]);
        lpo++;
    }
    while (rpo <= r) {
        pair<int, double> rpl = quest(1, tmp[rpo].v, n);
        if (rpl.first + 1 > dp1[tmp[rpo].pos]) {
            dp1[tmp[rpo].pos] = rpl.first + 1;
            f1[tmp[rpo].pos] = rpl.second;
        } else if (rpl.first + 1 == dp1[tmp[rpo].pos]) {
            f1[tmp[rpo].pos] += rpl.second;
        }
        rpo++;
    }
    for (int i = l; i <= mid; i++) {
        clear(1, query[i].v);
    }//清空 
    solve(mid + 1, r);//处理右区间 
    sort(query + l, query + r + 1);
}
void Solve(int l, int r) {//处理逆序 
    if (l == r) {
        return;
    }
    int mid = (l + r) >> 1;
    Solve(l, mid);
    int lpo = l;
    int rpo = mid + 1;
    for (int i = mid + 1; i <= r; i++) {
        tmpx[i] = queryx[i];
    }
    sort(tmpx + mid + 1, tmpx + r + 1);
    while (lpo <= mid && rpo <= r) {
        if (queryx[lpo].h <= tmpx[rpo].h) {//不下降 
            update(1, queryx[lpo].v, dp2[queryx[lpo].pos], f2[queryx[lpo].pos]);
            lpo++;//前缀最大 
        } else {
            pair<int, double> rpl = quest(1, 1, tmpx[rpo].v);
            if (rpl.first + 1 > dp2[tmpx[rpo].pos]) {
                dp2[tmpx[rpo].pos] = rpl.first + 1;
                f2[tmpx[rpo].pos] = rpl.second;
            } else if (rpl.first + 1 == dp2[tmpx[rpo].pos]) {
                f2[tmpx[rpo].pos] += rpl.second;
            }
            rpo++;
        }
    }
    while (lpo <= mid) {
        update(1, queryx[lpo].v, dp2[queryx[lpo].pos], f2[queryx[lpo].pos]);
        lpo++;
    }
    while (rpo <= r) {
        pair<int, double> rpl = quest(1, 1, tmpx[rpo].v);
        if (rpl.first + 1 > dp2[tmpx[rpo].pos]) {
            dp2[tmpx[rpo].pos] = rpl.first + 1;
            f2[tmpx[rpo].pos] = rpl.second;
        } else if (rpl.first + 1 == dp2[tmpx[rpo].pos]) {
            f2[tmpx[rpo].pos] += rpl.second;
        }
        rpo++;
    }
    for (int i = l; i <= mid; i++) {
        clear(1, queryx[i].v);
    }
    Solve(mid + 1, r);
    sort(queryx + l, queryx + r + 1);
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d %d", &query[i].h, &query[i].v);
        query[i].pos = i;
        lsh[i] = query[i].h;
        dp1[i] = 1;
        f1[i] = 1.0;
        dp2[i] = 1;
        f2[i] = 1.0;//初值 
    }
    sort(lsh + 1, lsh + 1 + n);
    int cnt_lsh = unique(lsh + 1, lsh + 1 + n) - lsh - 1;
    for (int i = 1; i <= n; i++) {
        query[i].h = lower_bound(lsh + 1, lsh + 1 + cnt_lsh, query[i].h) - lsh;
    }//离散化 
    for (int i = 1; i <= n; i++) {
        lsh[i] = query[i].v;
    }
    sort(lsh + 1, lsh + 1 + n);
    cnt_lsh = unique(lsh + 1, lsh + 1 + n) - lsh - 1;
    for (int i = 1; i <= n; i++) {
        query[i].v = lower_bound(lsh + 1, lsh + 1 + cnt_lsh, query[i].v) - lsh;
    }
    for (int i = 1; i <= n; i++) {
        queryx[i].h = query[n - i + 1].h;
        queryx[i].v = query[n - i + 1].v;
        queryx[i].pos = n - i + 1;//逆序存储 
    }
    Build(1, 1, n);
    solve(1, n);
    int maxans = 0;
    for (int i = 1; i <= n; i++) {
        maxans = max(maxans, dp1[i]);
        //		printf("%d %d\n",dp1[i],f1[i]);
    }
    printf("%d\n", maxans);
    double tot = 0;
    for (int i = 1; i <= n; i++) {
        if (dp1[i] == maxans) {
            tot += f1[i];
        }
    }//统计总方案 
    Build(1, 1, n);
    Solve(1, n);
    for (int i = 1; i <= n; i++) {
        //	printf("%d ",dp2[i]);
        if ((dp1[i] + dp2[i] - 1) == maxans) {//考虑是否可能为最大 
            printf("%.6lf ", (f1[i] * 1.0 / tot) * f2[i]);
        } else {
            printf("0 ");
        }
        // printf("\n");
    }
}
posted @ 2022-02-12 22:08  kid_magic  阅读(21)  评论(0编辑  收藏  举报