题目链接:【codeforces 629D】 HDU1087的升级版
有n个圆柱形的蛋糕,已知每个蛋糕的半径r和高h,将这n个蛋糕叠起来,第i个蛋糕能放在第j个蛋糕的上面(1<=j<i)的条件:第i个蛋糕的体积>第j个蛋糕的体积,问最终叠成的蛋糕的最大体积
dp[i] = max(dp[j], 1<=j<i&&a[j]<a[i]) + vol[i],这一题这样做会超时
【线段树】
用线段树记录第i个蛋糕之前满足条件的的最大dp值
将从小到大排序后的体积的序号作为线段树的下标,每访问一次vol[i],就把相应的dp[i]插入到线段树中,更新最大值
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const int inf=1e5+10;
const double pi=acos(-1.0);
ll dp[inf], vol[inf], a[inf];
struct node
{
int l, r;
ll maxn;
}T[inf*4];
void build(int l, int r, int u)
{
T[u].maxn=0;
T[u].l = l, T[u].r = r;
if(l==r) return;
int mid = (l+r)>>1;
build(l, mid, u<<1);
build(mid+1, r, u<<1|1);
}
ll query(int li, int ri, int u)
{
if(li==T[u].l && ri==T[u].r) return T[u].maxn;
int mid = (T[u].l+T[u].r)>>1;
if(ri<=mid) return query(li, ri, u<<1);
else if(li>mid) return query(li, ri, u<<1|1);
else return max(query(li, mid, u<<1), query(mid+1, ri, u<<1|1));
}
void update(int id, int i, int u)
{
if(T[u].l==T[u].r)
{
if(T[u].l==id) T[u].maxn = max(T[u].maxn, dp[i]);
return;
}
int mid = (T[u].l+T[u].r)>>1;
if(id<=mid) update(id, i, u<<1);
if(id>mid) update(id, i, u<<1|1);
T[u].maxn = max(T[u<<1].maxn, T[u<<1|1].maxn);
}
int main()
{
int n;
ll r, h;
scanf("%d", &n);
for(int i=1; i<=n; i++)
{
scanf("%I64d%I64d", &r, &h);
a[i] = vol[i] = r*r*h;
}
sort(a+1, a+1+n);
int num = unique(a+1, a+1+n)-a-1;
build(1, num, 1);
ll mmaxn = -1e18;
for(int i=1; i<=n; i++)
{
int id = lower_bound(a+1, a+1+num, vol[i])-a;
if(id==1) dp[i] = vol[i];
else dp[i] = query(1, id-1, 1) + vol[i];
mmaxn = max(mmaxn, dp[i]);
update(id, i, 1);
}
// cout<<mmaxn<<endl;
printf("%.12lf\n", pi*mmaxn);
return 0;
}
【树状数组】
BIT[i]:保存的是max(dp[j], j<=i&&a[j]<a[i])
#include <bits/stdc++.h>
using namespace std;
#define ll __int64
const double pi=acos(-1.0);
const int inf=1e5+10;
ll a[inf], vol[inf], dp[inf], BIT[inf];
ll r, h;
int lowbit(int x)
{
return x&-x;
}
ll query(int id)
{
ll ans = 0;
for(;id;id-=lowbit(id)) ans = max(ans, BIT[id]);
return ans;
}
void insert(int id, ll x)
{
for(;id<inf;id+=lowbit(id))
BIT[id] = max(BIT[id], x);
}
int main()
{
int n;
scanf("%d", &n);
for(int i=1;i<=n; i++)
{
scanf("%I64d%I64d", &r, &h);
a[i] = vol[i] = r*r*h;
}
sort(a+1, a+1+n);
int num = unique(a+1, a+1+n)-a-1;
ll maxn = -1e18;
for(int i=1; i<=n; i++)
{
int id = lower_bound(a+1, a+1+num, vol[i])-a;
dp[i] = query(id-1) + vol[i];
maxn = max(dp[i], maxn);
insert(id, dp[i]);
}
printf("%.12lf\n", pi*maxn);
return 0;
}