最长上升序列变形。LIS线段树写法。
#include<cstdio> #include<cstring> #include<cmath> #include<string> #include<vector> #include<queue> #include<algorithm> #include<iostream> using namespace std; const int maxn = 100000 + 10; struct X { long long r, h; int id; }s[maxn]; int n; long long MAX[4 * maxn]; long long ans; long long f[maxn]; long long pri; double pi = acos(-1.0); bool cmp(const X&a, const X&b) { if (a.r*a.r*a.h == b.r*b.r*b.h) return a.id>b.id; return a.r*a.r*a.h<b.r*b.r*b.h; } void read() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d%d", &s[i].r, &s[i].h); s[i].id = i; } } void pushUp(int rt) { MAX[rt] = max(MAX[2 * rt], MAX[2 * rt + 1]); } void build(int l, int r, int rt) { if (l == r) { MAX[rt] = 0; return; } int m = (l + r) / 2; build(l, m, 2 * rt); build(m + 1, r, 2 * rt + 1); pushUp(rt); } void quary(int L, int R, int l, int r, int rt) { if (L <= l&&r <= R) { ans = max(ans, MAX[rt]); return; } int m = (l + r) / 2; if (L <= m) quary(L, R, l, m, 2 * rt); if (R >= m + 1) quary(L, R, m + 1, r, 2 * rt + 1); } void update(int pos, int l, int r, int rt) { if (l == r) { MAX[rt] = ans; return; } int m = (l + r) / 2; if (pos <= m) update(pos, l, m, 2 * rt); if (pos>m) update(pos, m + 1, r, 2 * rt + 1); pushUp(rt); } void work() { build(1, n, 1); sort(s + 1, s + 1 + n, cmp); pri = 0; for (int i = 1; i <= n; i++) { ans = 0; quary(1, s[i].id, 1, n, 1); ans = s[i].r*s[i].r*s[i].h + ans; update(s[i].id, 1, n, 1); pri = max(pri, ans); } // printf("%lld ", pri); printf("%.10lf ", (double)pri*pi); } int main() { read(); work(); return 0; }