首先要明白一个蛋糕在另一个之上当且仅当序号和体积都比原来的大
然后一维显然可以用sort解决,另一维暴力是n^2显然过不了,考虑优化
不妨按体积排序,然后记录对应的在原序列中的序号,然后扫一遍,每次处理完当前之后,便把这个体积插入线段树中,对应的节点就是在原序列中对应的节点,然后每次用logn做大查询,就是简单的线段树优化DP的问题。
当然,比如树状数组等同样支持区间Max的也能做到
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <string>
#define mod 1000000007
#define ll long long
#define rep(i, j, k) for(int i = j; i <= k; i++)
using namespace std;
int n;
ll Max[11 * 100009];
ll f[100009];
struct cadongllas
{
ll r, h;
int num;
}a[100009];
ll calc (cadongllas x)
{
return x.r * x.r * x.h;
}
bool cmp (cadongllas x, cadongllas y)
{
return ((calc (x) < calc (y)) || (calc (x) == calc (y) && x.num > y.num));
}
void insert (int x, int l, int r, int location, ll sum)
{
if (location > r || location < l)
return;
if (l == r)
{
if (l == location)
Max[x] = sum;
return;
}
int mid = (l + r) >> 1;
insert (2 * x, l, mid, location, sum);
insert (2 * x + 1, mid + 1, r, location, sum);
Max[x] = max (Max[2 * x], Max[2 * x + 1]);
}
ll ask (int x, int l, int r, int location)
{
if (l > location)
return 0;
if (r < location)
return Max[x];
if (l == r)
{
if (l == location)
return Max[x];
else
return 0;
}
int mid = (l + r) >> 1;
return max (ask (2 * x, l, mid, location), ask (2 * x + 1, mid + 1, r, location));
}
int main ()
{
scanf ("%d", &n);
rep (i, 1, n)
cin >> a[i].r >> a[i].h, a[i].num = i;
sort (a + 1, a + 1 + n, cmp);
f[1] = calc (a[1]);
insert (1, 1, n, a[1].num, f[1]);
ll ans = 0;
rep (i, 2, n)
{
ll now = ask (1, 1, n, a[i].num - 1) + calc (a[i]);
insert (1, 1, n, a[i].num, now);
}
double Ans;
Ans = acos (-1.0) * ask (1, 1, n, n);
printf ("%.9lf\n", Ans);
return 0;
}