- 求上升子序列的最大和。O(n^2)会暴力,在查询的时候要用线段树维护
- 因为权值是浮点数,故先离散化一下,设第 i 个位置的权值,从小到大排名为 id。那么dp转移中 \[d[i] = max(d[i],d[i] + d[j])\] 其中\[j<i \& id[j]<id[i]\] 故线段树结点区间
[l,r]
维护的是id = l 到 id = j 中的最大 dp值
#include <bits/stdc++.h>
using namespace std;
const int N = 100000;
double vol[N],r,h;
int n,has[N],g[N],dp[N],tot;
int c[N];
vector<double> v;
int getId(double a){
return lower_bound(v.begin(),v.end(),a)-v.begin()+1;
}
struct Tree{
int l,r;
double data;
}t[4*N];
void build(int p,int l,int r){
t[p].l = l;
t[p].r = r;
if(l==r){
t[p].data = 0;return;
}
int mid = l+r>>1;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].data = 0;
}
void change(int p,int x,double val){
if(t[p].l == t[p].r && t[p].l == x){
t[p].data = max(t[p].data,val);
return ;
}
int mid = (t[p].l+t[p].r)>>1;
if(x<=mid)change(p*2,x,val);
else change(p*2+1,x,val);
t[p].data = max(t[p*2].data,t[p*2+1].data);
}
double ask(int p,int l,int r){
if(t[p].l>=l&&t[p].r<=r)return t[p].data;
int mid = (t[p].l+t[p].r)>>1;
double val = 0;
if(l<=mid)val = max(val,ask(p*2,l,r));
if(r>mid)val = max(val,ask(p*2+1,l,r));
return val;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%lf%lf",&r,&h);
vol[i] = acos(-1) * r * r * h;
v.push_back(vol[i]);
}
sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());
build(1,1,n);
double res = 0;
for(int i=1;i<=n;i++){
int id = getId(vol[i]);
double now = ask(1,1,id-1);
now = max(vol[i],vol[i]+now);
res = max(res,now);
change(1,id,now);
}
printf("%.10lf\n",res);
return 0;
}
- 辗转了很多次,惭愧,线段树做的题太少了
法二:离散化+树状数组
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
const int inf = 0x3f3f3f3f;
double vol[N],c[N];
vector<double> v;
int n,g[N];
int getId(double res){
return lower_bound(v.begin(),v.end(),res) - v.begin() + 1;
}
void add(int x,double y){
c[x] = y;
for(;x<=n;x+=x&-x)c[x] = max(c[x],y);
}
double ask(int x){
double res = 0;
for(;x;x-=x&-x)res = max(res,c[x]);
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
double r,h;
scanf("%lf%lf",&r,&h);
double vo = acos(-1) * r * r * h;
vol[i] = vo;
v.push_back(vo);
}
sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());
double res = 0;
for(int i=1;i<=n;i++){
int x = getId(vol[i]);
double now = ask(x-1) + vol[i];
add(x,now);
res = max(res,now);
}
printf("%.10lf\n",res);
return 0;
}