#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <stack>
#include <list>
#include <utility>
#include <vector>
#include <set>
#include <algorithm>
#include <cmath>
#include <climits>
#include <map>
#include <unordered_map>
#include <string.h>
#include<iomanip>
#include <iterator>

#define all(a) a.begin(),a.end()
#define VV(T) vector<vector< T > >
#define rep(i,N) for(int i = 0; i <N; i++)
#define name(x) #x
using namespace std;


const int INF = INT_MAX;
const long long INFL = (1LL<<40);
const int MOD = pow(10,9)+7;
int dy[]={0, 0, 1, -1, 0};
int dx[]={1, -1, 0, 0, 0};

typedef long long ll,LL;
typedef vector<int> vint;
typedef vector<vector<int> > vvint;
typedef vector<long long> vll, vLL;
typedef vector<vector<long long> > vvll, vvLL;
typedef pair<int,int> pii;
typedef pair<LL, LL> pLL;


// vector入力
template<typename T>
istream& operator >> (istream& is, vector<T>& vec){
    for(T& x: vec) is >> x;
    return is;
}
// vector出力
template<typename T>
ostream& operator << (ostream& os, vector<T>& vec){
    for(int i=0; i<vec.size(); i++){
        os << vec[i] << ( i+1 == vec.size() ? "" : " " );
    }
    return os;
}



template<typename T>
struct SegmentTree {
private:
    int n;
    vector<T> node;
public:
    // 元配列 v をセグメント木で表現する. 操作は半開区間
    SegmentTree(vector<T> v) {
        // 最下段のノード数は元配列のサイズ以上になる最小の 2 冪 -> これを n とおく
        // セグメント木全体で必要なノード数は 2n-1 個である
        int sz = (int)v.size();
        n = 1; while(n < sz) n *= 2;
        node.resize(2*n-1, -INFL);
        
        // 最下段に値を入れたあとに、下の段から順番に値を入れる
        // 値を入れるには、自分の子の 2 値を参照すれば良い
        for(int i=0; i<sz; i++) node[i+n-1] = v[i];
        for(int i=n-2; i>=0; i--) node[i] = max(node[2*i+1], node[2*i+2]);
    }
    
    // x番目の要素をvalに変更する。
    void update(int x, T val) {
        // 最下段のノードにアクセスする
        x += (n - 1);
        
        // 最下段のノードを更新したら、あとは親に上って更新していく
        node[x] = val;
        while(x > 0) {
            x = (x - 1) / 2;
            node[x] = max(node[2*x+1], node[2*x+2]);
        }
    }
    // 要求区間 [a, b) 中の要素の最小値を答える
    // k := 自分がいるノードのインデックス
    // 対象区間は [l, r) にあたる
    
    T getmax(int a, int b, int k=0, int l=0, int r=-1) {
        // 最初に呼び出されたときの対象区間は [0, n)
        if(r < 0) r = n;
        
        // 要求区間と対象区間が交わらない -> 適当に返す
        if(r <= a || b <= l) return -INFL;
        
        // 要求区間が対象区間を完全に被覆 -> 対象区間を答えの計算に使う
        if(a <= l && r <= b) return node[k];
        
        // 要求区間が対象区間の一部を被覆 -> 子について探索を行う
        // 左側の子を vl ・ 右側の子を vr としている
        // 新しい対象区間は、現在の対象区間を半分に割ったもの
        T vl = getmax(a, b, 2*k+1, l, (l+r)/2);
        T vr = getmax(a, b, 2*k+2, (l+r)/2, r);
        return max(vl, vr);
    }
    
    
};



const int MAX_SIZE = 200005;
ll memo[MAX_SIZE];
int N;
vint a;
vint h;

int main() {
    cin >> N;
    a.resize(N+1);
    h.resize(N+1);
    
    for(auto i = 1; i<=N; i++){
        cin >> h[i];
    }
    for(auto i = 1; i<=N; i++){
        cin >> a[i];
    }
    
    vector<ll> dp(N,0);
    SegmentTree<ll> seg(dp);
    
    seg.update(h[1]-1,a[1]);
    
    for(auto i = 2; i<=N; i++){
        
        seg.update(h[i]-1,a[i] + seg.getmax(0,h[i]));
        
    }
    
    cout << seg.getmax(0,N)<<endl;
    
    
    
    return 0;
}




Measured memory_bytes: 9088