拦截导弹
\[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");
}
}