// #pragma comment(linker, "/stack:200000000")
// #pragma GCC optimize("O3")
// #pragma GCC optimize("Ofast")
// #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
// #pragma GCC optimize("unroll-loops")

#include<bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#ifdef on_linux
#include <sys/resource.h>
#endif

using namespace std;
using namespace __gnu_pbds;

#ifdef dobby_is_a_free_elf
#define TRACE
#endif
#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1) {
    cout << name << " : " << arg1 << std::endl;
    //use cerr if u want to display at the bottom
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args) {
    const char* comma = strchr(names + 1, ','); cout.write(names, comma - names) << " : " << arg1 << " | "; __f(comma + 1, args...);
}
#else
#define trace(...)
#endif

#define all(x)                  (x).begin(), (x).end()
#define fi                      first
#define GCD(x,y)                (__gcd((x), (y)))
#define int                     long long
#define lbd                     lower_bound
#define LCM(x,y)                (((x)/__gcd((x), (y)))*(y))
#define mem0(x)                 memset(x, 0, sizeof (x))
#define mem1(x)                 memset(x, -1, sizeof (x))
#define mp                      make_pair
#define pb                      push_back
#define pf                      push_front
#define pob                     pop_back
#define pof                     pop_front
#define rep(i,begin,end)        for(__typeof(end) i=(begin)-((begin)>(end));i!=(end)-((begin)>(end));i+=1-2*((begin)>(end)))
#define sc                      second
#define sleep(x)                std::this_thread::sleep_for(std::chrono::milliseconds(x))
#define sz(x)                   (int)((x).size())
#define ubd                     upper_bound

struct ConfigIO {
    ConfigIO() {
        cin.tie(nullptr);
        cout.tie(nullptr);
        ios_base::sync_with_stdio(false);   // using both C and C++ streams will now mix up the outputs (also inputs)
    }
} cnf_io;

// struct config_rand {
//    config_rand() {
//        srand(chrono::duration_cast<chrono::nanoseconds>(
//                chrono::high_resolution_clock::now().time_since_epoch()).count());
//    }
// } cnf_rand;

// int GetRand() {
//  static mt19937_64 gen;
//  static uniform_int_distribution<int> dis;
//  return dis(gen);
// }

template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
// find_by_order(k)  returns iterator to kth element starting from 0;
// order_of_key(k) returns count of elements strictly smaller than k;
// erase,insert same as normal set

template <typename T>
using min_pq = priority_queue<T, vector<T>, greater<T>>;

inline long long toint(const string &s) {stringstream ss; ss << s; long long x; ss >> x; return x;}
inline string tostring(long long number) {stringstream ss; ss << number; return ss.str();}
inline string tobin(long long x) {return bitset<63>(x).to_string();}

// __builtin_popcount(x) - Returns the number of 1-bits in x.
// __builtin_parity(x) - Returns the parity of x, i.e. the number of 1-bits in x
// modulo 2.
// __builtin_ffs(x) - Returns one plus the index of the least significant 1-bit
// of x, or if x is zero, returns zero.
// __builtin_clz(x) - Returns the number of leading 0-bits in x, starting at the
// most significant bit position. If x is 0, the result is undefined.
// __builtin_ctz(x) - Returns the number of trailing 0-bits in x, starting at
// the least significant bit position. If x is 0, the result is undefined.

/*----------------------Graph Moves----------------------*/
// const int fx[]={+1,-1,+0,+0};
// const int fy[]={+0,+0,+1,-1};
// const int fx[]={+0,+0,+1,-1,-1,+1,-1,+1};   // Kings Move
// const int fy[]={-1,+1,+0,+0,+1,+1,-1,-1};  // Kings Move
// const int fx[]={-2, -2, -1, -1,  1,  1,  2,  2};  // Knights Move
// const int fy[]={-1,  1, -2,  2, -2,  2, -1,  1}; // Knights Move
/*-------------------------------------------------------*/

// primes for hashing 937,991,1013,1409,1741
// or use hash<string> hasher; hasher("qwerty");
// or hash<string>{}("qwerty");

const long long INF = 1e18;
const long long MOD = 1e9 + 7;
const long long fftmod = 998244353;
const long double PI = 3.14159265358979323846264338;
const long double eps = 1e-12;
const int N = 2e5 + 10;

// big mod and primitive root for NTT:
// #define MOD 2305843009255636993          // a bit larger than 2^61
// #define RT 5


inline void precompute()
{

    return;
}
int dp[N];

// A utility function to get the
// middle index of given range.
int getMid(int s, int e)
{
    return s + (e - s) / 2;
}

/*  A recursive function to get the sum of
    values in given range of the array.
    The following are parameters for this
    function.

    st       -> Pointer to segment tree
    node     -> Index of current node in
                the segment tree .
    ss & se  -> Starting and ending indexes
                of the segment represented
                by current node, i.e., st[node]
    l & r    -> Starting and ending indexes
                of range query */
int MaxUtil(int* st, int ss, int se, int l,
            int r, int node)
{
    // If segment of this node is completely
    // part of given range, then return
    // the max of segment
    if (l <= ss && r >= se)
        return st[node];

    // If segment of this node does not
    // belong to given range
    if (se < l || ss > r)
        return -1;

    // If segment of this node is partially
    // the part of given range
    int mid = getMid(ss, se);

    return max(MaxUtil(st, ss, mid, l, r,
                       2 * node + 1),
               MaxUtil(st, mid + 1, se, l,
                       r, 2 * node + 2));
}

/* A recursive function to update the nodes which
   have the given index in their range. The following
   are parameters st, ss and se are same as defined
   above index -> index of the element to be updated.*/
void updateValue(int arr[], int* st, int ss, int se,
                 int index, int value, int node)
{
    if (index < ss || index > se)
    {
        cout << "Invalid Input" << endl;
        return;
    }

    if (ss == se)
    {
        // update value in array and in segment tree
        arr[index] = value;
        st[node] = value;
    }
    else {
        int mid = getMid(ss, se);

        if (index >= ss && index <= mid)
            updateValue(arr, st, ss, mid, index,
                        value, 2 * node + 1);
        else
            updateValue(arr, st, mid + 1, se,
                        index, value, 2 * node + 2);

        st[node] = max(st[2 * node + 1],
                       st[2 * node + 2]);
    }
    return;
}

// Return max of elements in range from
// index l (query start) to r (query end).
int getMax(int* st, int n, int l, int r)
{
    // Check for erroneous input values
    if (l < 0 || r > n - 1 || l > r)
    {
        printf("Invalid Input");
        return -1;
    }

    return MaxUtil(st, 0, n - 1, l, r, 0);
}

// A recursive function that constructs Segment
// Tree for array[ss..se]. si is index of
// current node in segment tree st
int constructSTUtil(int arr[], int ss, int se,
                    int* st, int si)
{
    // If there is one element in array, store
    // it in current node of segment tree and return
    if (ss == se)
    {
        st[si] = arr[ss];
        return arr[ss];
    }

    // If there are more than one elements, then
    // recur for left and right subtrees and
    // store the max of values in this node
    int mid = getMid(ss, se);

    st[si] = max(constructSTUtil(arr, ss, mid, st,
                                 si * 2 + 1),
                 constructSTUtil(arr, mid + 1, se,
                                 st, si * 2 + 2));

    return st[si];
}

/* Function to construct segment tree from given array.
   This function allocates memory for segment tree.*/
int* constructST(int arr[], int n)
{
    // Height of segment tree
    int x = (int)(ceil(log2(n)));

    // Maximum size of segment tree
    int max_size = 2 * (int)pow(2, x) - 1;

    // Allocate memory
    int* st = new int[max_size];

    // Fill the allocated memory st
    constructSTUtil(arr, 0, n - 1, st, 0);

    // Return the constructed segment tree
    return st;
}

inline void dobbysolver(int testcase)
{
    int n;
    cin >> n;
    int h[n], a[n];
    for (int i = 0; i < n; ++i)
        cin >> h[i];
    for (int i = 0; i < n; ++i)
        cin >> a[i];
    int *st = constructST(dp, N);
    updateValue(dp, st, 0, N - 1, h[0], a[0], 0);

    for (int i = 1; i < n; ++i)
    {
        int ans;
        ans = getMax(st, N, 0, h[i] - 1) + a[i];
        // dp[h[i]] = ans;
        updateValue(dp, st, 0, N - 1, h[i], ans, 0);
        // trace(i, ans);
    }
    int ans = 0;
    for (int i = 0; i < N; ++i)
        ans = max(ans, dp[i]);
    cout << ans;
    return;
}

int32_t main() {
#ifdef on_linux
    rlimit cpu_time {.rlim_cur = 2, .rlim_max = RLIM_INFINITY};
    setrlimit(RLIMIT_CPU, &cpu_time);
    /*
    struct rlimit {
        rlim_t rlim_cur;  // Soft limit
        rlim_t rlim_max;  // Hard limit (ceiling for rlim_cur)
    };
    */
#endif
    precompute();
    int TESTS = 1;
    //cin >> TESTS;
    for (int i = 1; i <= TESTS; ++i) {dobbysolver(i); if (i != TESTS) cout << '\n';}
    return 0;
}

Measured memory_bytes: 9088