朴素的做法就是二元组 序列的 LIS dp,同时维护 LIS 的数量。 可在 决策的条件是 (将时间视为下标)。
于是联想到使用 cdq dac 优化,使用树状数组 / 线段树支持单点合并 dp 值,最大值。
然后,,第二问要维护反转过来的 dp 值,再跑一遍就行了。
说几个坑点,在 dac 时 给 dp 赋初值时,dp 在 上的点值不一定是第一次被访问,所以不能简单的赋为 ,要取 max(对着 xtw 的代码灵魂对照才找出来 憨笑)。
因为 的 dp 决策是对 的决策有影响的,所以不能先把左右两边跑完再计算跨区间贡献,而是应该先把 跑完,然后再跑右区间。这又带来一个细节,对左右区间的以 为关键字的排序会使得原区间的 (下标)无序,需要在递归之前排回来。
#include <bits/stdc++.h>
using namespace std;
#define cmin(x, y) x = min(x, y)
#define cmax(x, y) x = max(x, y)
#define fors(i, l, r, ...) for(int i = (l), REP##i = (r), ##__VA_ARGS__; i <= REP##i; ++i)
#define dfors(i, r, l, ...) for(int i = (r), REP##i = (l), ##__VA_ARGS__; i >= REP##i; --i)
int f1[50100], f2[50100];
double g1[50100], g2[50100];
int n, _n;
struct request {
int t, x, y;
} req[50100], tmp[50100];
struct S {
int x = 0;
double p = 0;
} bit[50100];
void merge(S& x, const S& y) {
if(x.x > y.x) x = x;
else if(x.x < y.x) x = y;
else x = (S){x.x, x.p+y.p};
}
void add(int x, const S& v) {
for(; x; x -= x&-x) merge(bit[x], v);
}
void reset(int x) {
for(; x; x -= x&-x) bit[x] = (S){0, 0};
}
S ask(int x) {
S res;
for(; x <= _n; x += x&-x) merge(res, bit[x]);
return res;
}
void solve(const int l, const int r, int f[], double g[]) {
if(l == r) {
cmax(f[req[l].t], 1), g[req[l].t] += f[req[l].t] == 1;
return;
}
int mid = (l+r)>>1;
sort(req+l, req+r+1,
[](const request& lhs, const request& rhs) { return lhs.t < rhs.t; });
solve(l, mid, f, g);
sort(req+l, req+mid+1,
[](const request& lhs, const request& rhs) { return lhs.y > rhs.y; });
sort(req+mid+1, req+r+1,
[](const request& lhs, const request& rhs) { return lhs.y > rhs.y; });
int j = l;
fors(i, mid+1, r) {
for(; j <= mid && req[j].y >= req[i].y; ++j) add(req[j].x, (S){f[req[j].t], g[req[j].t]});
S ret = ask(req[i].x);
if(ret.x == 0) continue;
if(f[req[i].t] < ret.x+1) f[req[i].t] = ret.x+1,g[req[i].t] = ret.p;
else if(f[req[i].t] == ret.x+1) g[req[i].t] += ret.p;
}
fors(i, l, j) reset(req[i].x);
solve(mid+1, r, f, g);
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n;
vector<int> v;
fors(i, 1, n) {
cin >> req[i].x >> req[i].y;
req[i].t = i;
v.emplace_back(req[i].x);
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
_n = static_cast<int>(v.size());
fors(i, 1, n) req[i].x = lower_bound(v.begin(), v.end(), req[i].x)-v.begin()+1;
solve(1, n, f1, g1);
int max_f1 = *max_element(f1+1, f1+n+1);
double sum_g1 = 0;
fors(i, 1, n) sum_g1 += (max_f1 == f1[i])*g1[i];
fors(i, 1, n) req[i].t = n-req[i].t+1,req[i].x = _n-req[i].x+1,req[i].y *= -1;
solve(1, n, f2, g2);
reverse(f2+1, f2+n+1);
reverse(g2+1, g2+n+1);
cout << max_f1 << "\n";
fors(i, 1, n) cout << (f1[i]+f2[i]-1 == max_f1 ? g1[i]*g2[i]/sum_g1 : 0.0) << " \n"[i == n];
return 0;
}