P5381 [THUPC2019] 不等式

发布时间 2023-09-25 15:53:08作者: zltzlt

洛谷传送门

首先特判 \(a_i = 0\),然后:

\(\begin{aligned} f_k(x) & = \sum\limits_{i = 1}^k |a_i x + b_i| \\ & = \sum\limits_{i = 1}^k a_i |x + \frac{b_i}{a_i}| \end{aligned}\)

默认 \(a_i > 0\),若不满足则 \(a_i, b_i\) 同时取相反数即可。

然后这个东西就变成了,数轴上 \(-\frac{b_i}{a_i}\) 位置上有 \(a_i\) 个点,找一个点使这个点到所有点的距离最小。

根据小学奥数,取所有 \(-\frac{b_i}{a_i}\) 的中位数(设为 \(p\))最优。然后把 \(p\) 代入上面式子,拆绝对值即可。

使用树状数组求中位数和维护 \(\sum a_i, \sum b_i\),复杂度 \(O(n \log n)\)

code
// Problem: P5381 [THUPC2019] 不等式
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5381
// Memory Limit: 500 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mkp make_pair
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;

struct frac {
	ll x, y;
	frac(ll a = 0, ll b = 1) {
		if (b < 0) {
			a = -a;
			b = -b;
		}
		x = a;
		y = b;
	}
};

inline bool operator < (const frac &a, const frac &b) {
	return a.x * b.y < a.y * b.x;
}

inline bool operator == (const frac &a, const frac &b) {
	return a.x * b.y == a.y * b.x;
}

const int maxn = 500100;

ll n, tot;
frac lsh[maxn];
struct node {
	ll a, b;
} a[maxn];

struct BIT {
	ll c[maxn];
	
	inline void update(int x, ll d) {
		for (int i = x; i <= tot; i += (i & (-i))) {
			c[i] += d;
		}
	}
	
	inline ll query(int x) {
		ll res = 0;
		for (int i = x; i; i -= (i & (-i))) {
			res += c[i];
		}
		return res;
	}
	
	inline int kth(ll k) {
		ll s = 0;
		int p = 0;
		for (int i = 18; ~i; --i) {
			if (p + (1 << i) <= tot && s + c[p + (1 << i)] < k) {
				s += c[p + (1 << i)];
				p += (1 << i);
			}
		}
		return p + 1;
	}
} t1, t2;

void solve() {
	scanf("%lld", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i].a);
	}
	for (int i = 1; i <= n; ++i) {
		scanf("%lld", &a[i].b);
		if (a[i].a < 0) {
			a[i].a = -a[i].a;
			a[i].b = -a[i].b;
		}
		if (a[i].a) {
			lsh[++tot] = frac(-a[i].b, a[i].a);
		}
	}
	sort(lsh + 1, lsh + tot + 1);
	tot = unique(lsh + 1, lsh + tot + 1) - lsh - 1;
	ll s = 0, r = 0;
	for (int i = 1; i <= n; ++i) {
		if (a[i].a) {
			int k = lower_bound(lsh + 1, lsh + tot + 1, frac(-a[i].b, a[i].a)) - lsh;
			t1.update(k, a[i].a);
			t2.update(k, a[i].b);
		} else {
			r += abs(a[i].b);
		}
		s += a[i].a;
		int t = t1.kth((s + 1) / 2);
		frac p = lsh[t];
		db res = t1.query(t) * (1. * p.x / p.y) + t2.query(t);
		res += -(t1.query(tot) - t1.query(t)) * (1. * p.x / p.y) - (t2.query(tot) - t2.query(t));
		printf("%.6lf\n", res + r);
	}
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}