dp+树状数组(最长上升子序列+树状数组)

There are N flowers arranged in a row. For each i (1iN), the height and the beauty of the i-th flower from the left is hihi and aiai, respectively. Here, h1,h2,,hN are all distinct.

Taro is pulling out some flowers so that the following condition is met:

  • The heights of the remaining flowers are monotonically increasing from left to right.

Find the maximum possible sum of the beauties of the remaining flowers.

Constraints

 

  • All values in input are integers.
  • 1N2×1e5
  • 1hiN
  • h1,h2,,hN are all distinct.
  • 1ai1e9

Input

 

Input is given from Standard Input in the following format:

NN
h1 h2  hN
a1 a2  aN

Output

 

Print the maximum possible sum of the beauties of the remaining flowers.

Sample Input 1

 

4
3 1 4 2
10 20 30 40

Sample Output 1

 

60

We should keep the second and fourth flowers from the left. Then, the heights would be 1,21,2 from left to right, which is monotonically increasing, and the sum of the beauties would be 20+40=6020+40=60.

Sample Input 2

 

1
1
10

Sample Output 2

 

10

The condition is met already at the beginning.

Sample Input 3

 

5
1 2 3 4 5
1000000000 1000000000 1000000000 1000000000 1000000000

Sample Output 3

 

5000000000

The answer may not fit into a 32-bit integer type.

Sample Input 4

 

9
4 2 5 8 3 6 1 7 9
6 8 8 4 6 3 5 7 5

Sample Output 4

 

31

We should keep the second, third, sixth, eighth and ninth flowers from the left.

题意:

给你 h数组和s数组
问你 h数组一直上升的序列中 s数组最大的和是多少

这个题就是dp[i]代表的是前i朵花,并且取第i朵的最大和,那么转移方程就是dp[i]=dp[j]+v[i](j<i,a[j]<a[i])

注意这个答案不是dp[n]而是max(dp[1],dp[2],dp[3]........)

然后如果你普通的写就是:

for(int i = 1;i<=n;++i)
    {
        for(int j = 1;j<i;++j)
        {
            if(h[i]>h[j])
            {
                dp[i] = max(dp[i],dp[j]+arr[i]);
                ans = max(ans,dp[i]);
            }
        }
   }

这样肯定会超时的,所以你可以用线段树或者树状数组来维护1到i-1的dp数组的最大值

线段树:

#include<iostream>
#include<algorithm>
#include<cstring>
typedef long long ll; 
using namespace std;
int n;
const int maxn=5e6+100;
ll h[maxn];
ll a[maxn];
ll dp[maxn];//dp[i]为前i个的最大值 
struct node{
    int l,r;
    ll ma;
}t[maxn];
void build(int p,int l,int r){
    t[p].l=l;
    t[p].r=r;
    if(l==r){
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    build(2*p,l,mid);
    build(2*p+1,mid+1,r);
}
void update(int p,int x,ll k){
    if(t[p].r==t[p].l){
        t[p].ma=k;
        return ;
    }
    int mid=(t[p].l+t[p].r)/2;
    if(x<=mid){
        update(2*p,x,k);
    }
    else{
        update(2*p+1,x,k);
    }
    t[p].ma=max(t[2*p].ma,t[2*p+1].ma);
} 
ll query(int p,int l,int r){
    if(l<=t[p].l&&r>=t[p].r){
        return t[p].ma;
    }
    ll ans=-1e18;
    int mid=(t[p].l+t[p].r)/2;
    if(l<=mid){
        ans=max(ans,query(2*p,l,r));
    } 
    if(r>mid){
        ans=max(ans,query(2*p+1,l,r));
    } 
    return ans;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>h[i]; 
    }
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,1,2e5+10);
    ll ma=0; 
    for(int i=1;i<=n;i++){
        ll z=query(1,1,h[i]); 
        dp[i]=(1ll)*(z+a[i]);
        update(1,h[i],dp[i]);
        ma=max(ma,dp[i]);
    }
    cout<<ma<<endl;
} 
/*
4
1 2 3 2 3
1 1 1 2 3
*/

树状数组:

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll; 
const int maxn=1e6+100;
ll dp[maxn];
int h[maxn];
ll a[maxn];
ll ans[maxn];
int n;
ll lowbit(int x){
    return x&-x;
}
void add(int x,ll k){
    for(int i=x;i<=n;i+=lowbit(i)){
        ans[i]=max(ans[i],k);
    } 
}
ll query(int x){
    ll z=0;
    for(int i=x;i>0;i-=lowbit(i)){
        z=max(z,ans[i]);
    } 
    return z;
} 
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>h[i];
    }
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    ll ma=0;
    for(int i=1;i<=n;i++){
        dp[i]=a[i]+query(h[i]);
        ma=max(ma,dp[i]);
        add(h[i],dp[i]); 
    }
    cout<<ma<<endl;
}

 

posted @ 2021-03-10 23:54  lipu123  阅读(132)  评论(0编辑  收藏  举报