注意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;
}