CF-629 D

  • 求上升子序列的最大和。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
",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
",res);
    return 0;
}

原文地址:https://www.cnblogs.com/1625--H/p/10661079.html