题目链接:
CF 629D Babaei and Birthday Cake
题意:
给出n个圆柱形蛋糕的半径和高,设两个蛋糕的序号分别为i,j,体积分别为val[i]和val[j],当i>j并且val[i]>val[j]时,第i块蛋糕可以放在第j块蛋糕上面;
问怎样叠放可以使蛋糕总体积最大?
分析:
类似最长上升子序列。比较容易想到dp状态转移方程是:
dp[i]=max(dp[i],dp[j]+val[i]),其中j<i且val[j]<val[i]。dp[i]
表示以第i块蛋糕为最顶部蛋糕的最大蛋糕体积。
但是这样肯定TLE。
查题解发现可以用线段树查询j。o(╯□╰)o
先要将所有体积离散化之后建立线段树树,然后按照蛋糕顺序依次查询,线段树中保存从一开始到当前区间右端点的叠加能得到的最大
蛋糕体积,查询的时候先找到离散化之后对应的下标,接着在线段树中查找从0到(下标-1)这个区间能得到的最大叠加蛋糕值,
因为建立线段树的时候叶子结点相当于是单个蛋糕体积递增的顺序建立的,查询0到(下标-1)区间就保证是【
i>j并且val[i]>val[j]
】
那么将查询得到的值+val[i]就同样得到了以第i块蛋糕为最顶部蛋糕的最大蛋糕体积,然后再将这个值更新到线段树中,这个就是单点更新。
//93MS 9900K
#include <cstdio>
#include <cstring>
#include <cmath>
#include <climits>
#include <algorithm>
#include <iostream>
#define lson(x) (x<<1)
#define rson(x) ((x<<1)|1)
using namespace std;
const int maxn=100010;
const double pi=acos(-1.0);
long long r,h,val[maxn],vval[maxn],ans;
struct SegTree{
int left,right;
long long max_val;
}segtree[maxn<<2];
inline void build(int left,int right,int cur)
{
segtree[cur].left=left;
segtree[cur].right=right;
segtree[cur].max_val=0;
if(left==right){
return ;
}
int mid=(left+right)>>1;
build(left,mid,lson(cur));
build(mid+1,right,rson(cur));
}
inline long long query(int a,int b,int cur)
{
if(a>b) return 0;
int left=segtree[cur].left;
int right=segtree[cur].right;
if(left==a&&right==b){
return segtree[cur].max_val;
}
int mid=(left+right)>>1;
if(a>mid) return query(a,b,rson(cur));
else if(b<=mid) return query(a,b,lson(cur));
else {
long long tmp1=query(mid+1,b,rson(cur));
long long tmp2=query(a,mid,lson(cur));
return max(tmp1,tmp2);
}
}
inline void update(int des,int cur,long long tmp_val)
{
int left=segtree[cur].left;
int right=segtree[cur].right;
if(left==right){
segtree[cur].max_val=max(segtree[cur].max_val,tmp_val);
return;
}
int mid=(left+right)>>1;
if(des<=mid) update(des,lson(cur),tmp_val);
else update(des,rson(cur),tmp_val);
segtree[cur].max_val=max(segtree[lson(cur)].max_val,segtree[rson(cur)].max_val);
}
int main()
{
//freopen("629Din.txt","r",stdin);
//freopen("629Dout.txt","w",stdout);
int n;
while(~scanf("%d",&n)){
for(int i=0;i<n;i++){
scanf("%I64d%I64d",&r,&h);
vval[i]=val[i]=r*r*h;
}
sort(vval,vval+n);
int tot=unique(vval,vval+n)-vval;
build(0,tot-1,1);
ans=0;
for(int i=0;i<n;i++){
int id=lower_bound(vval,vval+tot,val[i])-vval;
long long tmp=query(0,id-1,1);
ans=max(ans,tmp+val[i]);
//printf("i=%d id=%d ans=%lld\n",i,id,ans);
update(id,1,tmp+val[i]);
}
printf("%.10f\n",pi*ans);
}
return 0;
}