注意update函数赋值的那个形参val必须为long long,防止出现溢出错误。
对于任意位置i,求出1~i-1的区间内比a[i]小的数中的最大值,想到用线段树维护。
建立线段树有两种方法:
1种是按照原数组建立从1~n的线段树,遍历新数组。这时结构体排序要注意数值相等的相邻的数字,原有下标按照降序排列。
原因是这样在遍历排序后的数组时,线段树中[1,i)区间中不会因为有和自己数值相等,但下标小的元素影响区间最大值。
如果按照升序排序会WA
2.按照新数组建立从1~n的线段树,遍历原有数组。线段树查询区间的为1到比lower_bound(...)-1的位置。遍历原数组的好处是只用查找当前线段数中比a[i]小的所有元素的区间。不会有相同数值的元素影响结果的情况。
用map或者set也可以解。
用map的时候,建立<a[i],dp[a[i]>的map。用map的lower_bound函数找到比mp下标小的index中,dp值最大的item。
注意map会自动按照key的从小到大顺序排列。在处理的时候需要从lower_bound到end位置依次遍历,除去后面key>=a[i]的,且dp值小于等于当前位置dp值的item。这样才可以始终保证map通过lower_bound查找出来的那个lower_bound-1位置的dp值是前面最大的。
例子:5 1 6 2 5 7,5 2 3 2 3,5 1 6 2 3 4 5 7。第一个例子是要注意,当5处在a[1]位置时,后面再次出现5时,dp值会大于5。所以删除时与该元素key相同的元素,可能value更小。第二个例子中3的dp值始终为5,两个3的dp值是相等的。第一个例子中第2个5出现时,需要删除6 7这个元素,这样才保证局部最大。即保证了map中key升序的同时,value也升序。单调性。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define CLR(x) memset(x,0,sizeof(x))
#define ll long long
using namespace std;
int n;
ll tree[100010<<2],a[100010],b[100010],dp[100010];
void PushUp(int rt){
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){tree[rt]=0;return;}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(rt);
}
void update(int p,ll val,int l,int r,int rt){
if(l==r){tree[rt]=val;return;}
int m=(l+r)>>1;
if(p<=m) update(p,val,l,m,rt<<1);
else update(p,val,m+1,r,rt<<1|1);
PushUp(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R) return tree[rt];
int m=(l+r)>>1;
ll ans=0;
if(L<=m) ans=max(ans,query(L,R,l,m,rt<<1));
if(R>m) ans=max(ans,query(L,R,m+1,r,rt<<1|1));
return ans;
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
int r,h;
scanf("%d%d",&r,&h);
a[i]=b[i]=(ll)r*r*h;
}
sort(a+1,a+n+1);
build(1,n,1);
for(int i=1;i<=n;i++){
int pos=lower_bound(a+1,a+n+1,b[i])-a;
if(pos==1) dp[i]=b[i];
else dp[i]=query(1,pos-1,1,n,1)+b[i];
update(pos,dp[i],1,n,1);
}
printf("%.12f\n",M_PI*tree[1]);
}
}
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#define CLR(x) memset(x,0,sizeof(x))
#define ll long long
using namespace std;
struct node
{
ll v;
int id;
}a[100010];
int n;
ll tree[100010<<2],dp[100010];
bool cmp(node a,node b){
if(a.v==b.v)
return a.id>b.id;
return a.v<b.v;
}
void PushUp(int rt){
tree[rt]=max(tree[rt<<1],tree[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){
tree[rt]=0;
return;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(rt);
}
void update(int p,ll val,int l,int r,int rt){
if(l==r){
tree[rt]=val;
return;
}
int m=(l+r)>>1;
if(p<=m){
update(p,val,l,m,rt<<1);
}else{
update(p,val,m+1,r,rt<<1|1);
}
PushUp(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return tree[rt];
}
int m=(l+r)>>1;
ll ans=0;
if(L<=m){
ans=max(ans,query(L,R,l,m,rt<<1));
}
if(R>m){
ans=max(ans,query(L,R,m+1,r,rt<<1|1));
}
return ans;
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++){
int r,h;
scanf("%d%d",&r,&h);
a[i].v=(ll)r*r*h;
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
build(1,n,1);
ll ans=0;
for(int i=1;i<=n;i++){
if(a[i].id==1){
dp[a[i].id]=a[i].v;
}else{
dp[a[i].id]=query(1,a[i].id-1,1,n,1)+a[i].v;
}
update(a[i].id,dp[a[i].id],1,n,1);
ans=max(ans,dp[a[i].id]);
}
printf("%.9f\n",M_PI*ans);
}
}
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define ll long long
#define pi acos(-1.0)
#define maxn 100100
int main(){
int r,h,n;
scanf("%d",&n);
map<ll,ll> mp;
mp[0]=0;
for (int i=1;i<=n;i++){
scanf("%d%d",&r,&h);
ll v=(ll)r*r*h;
map<ll,ll>::iterator r=mp.lower_bound(v);
ll sv=(--r)->second+v;
for(r++;r!=mp.end()&&r->second<=sv;)
mp.erase(r++);
mp[v]=sv;
}
printf("%.10f\n",(--mp.end())->second * pi);
return 0;
}