#include <algorithm>
#include <array>
#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdint>
#include <cstdio>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <optional>
#include <queue>
#include <set>
#include <string>
#include <string_view>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;

int64_t read_int() {
    int64_t ret = 0, sgn = 1;
    int ch = getchar_unlocked();
    while (isspace(ch)) { ch = getchar_unlocked(); }
    if (ch == '-') { sgn = -1; ch = getchar_unlocked(); }
    for (; isdigit(ch); ch = getchar_unlocked())
        ret = (ret * 10) + (ch - '0');
    ungetc(ch, stdin);
    return sgn * ret;
}

#define REP(i, n) for (int i = 0; i < (int)(n); ++i)
#define FOR(i, a, b) for (int i = (int)(a); i < (int)(b); ++i)
#define ALL(c) (c).begin(), (c).end()

template <typename T> inline void assign_min(T& x, const T& value) noexcept { x = min(x, value); }
template <typename T> inline void assign_max(T& x, const T& value) noexcept { x = max(x, value); }

constexpr char LF = '\n';

//-------------------------------------------------------------------------------------------------

// hi以下の素数を小さい順に返す
// O(hi log(hi))
vector<int64_t> primes_under(int64_t hi) {
    vector<int64_t> primes;
    primes.push_back(2);
    for (int64_t i = 3; i <= hi; i += 2) {
        bool ok = true;
        for (auto p : primes) {
            if (p*p > hi) { break; }
            if (i % p == 0) {
                ok = false;
                break;
            }
        }
        if (ok) {
            primes.push_back(i);
        }
    }
    return primes;
}

// エラトステネスの篩
// O(n log log n)
vector<bool> sieve(int n) {
    vector<bool> is_prime(n, true);
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i < n; ++i) {
        for (int j = i + i; j < n; j += i) {
            is_prime[j] = false;
        }
    }
    return is_prime;
}

// nを素因数分解する
// 事前条件: primes は sqrt(n) 以下の素数をすべて含んでいなければならない
// O(sqrt(n))
vector<pair<int64_t, int64_t>> prime_factorization(const vector<int64_t>& primes, int64_t n) {
    vector<pair<int64_t, int64_t>> factors;
    for (auto p : primes) {
        if (p*p > n) { break; }
        int cnt = 0;
        while (n % p == 0) {
            n /= p;
            ++cnt;
        }
        if (cnt > 0) {
            factors.push_back({p, cnt});
        }
    }
    if (n > 1) {
        factors.push_back({n, 1});
    }
    return factors;
}

// すべての約数に対して f(divisor) を呼び出す。1は約数に含まない。
template <class Func>
void foreach_divisor(const vector<pair<int64_t, int>>& factors, Func f, int i = 0, int64_t d = 1) {
    if (i == (int)factors.size()) {
        if (d != 1) {
            f(d);
        }
    } else {
        auto [factor, power] = factors[i];
        for (int k = 0; k <= power; ++k) {
            if (k != 0) { d *= factor; }
            foreach_divisor(factors, f, i+1, d);
        }
    }
}

// pred(x) を区間[a, b)で定義された単調増加なbool値関数とする。
// このとき pred(x) = true となるような最小の x を返す。
// そのような x が存在しないときは b を返す。
template <class Pred>
int64_t find_minimum_solution(int64_t a, int64_t b, Pred pred) {
    // 不変条件: i<a ⇒ pred(i)=false, b<=i ⇒ pred(i)=true
    if (a == b) return b;
    int64_t m = a + (b - a) / 2;
    if (pred(m))
        return find_minimum_solution(a, m, pred);
    else
        return find_minimum_solution(m+1, b, pred);
}

// pred(x) を区間(a, b]で定義された単調減少なbool値関数とする。
// (定義域に注意!!)
// このとき pred(x) = true となるような最大の x を返す。
// そのような x が存在しないときは a を返す。
template <class Pred>
int64_t find_maximum_solution(int64_t a, int64_t b, Pred pred) {
    // 不変条件: i<=a ⇒ pred(i)=true, b<i ⇒ pred(i)=false
    if (a == b) return a;
    int64_t m = a + (b - a + 1) / 2;
    if (pred(m))
        return find_maximum_solution(m, b, pred);
    else
        return find_maximum_solution(a, m-1, pred);
}

int main() {
    auto N = read_int();
    auto primes = primes_under(sqrt(N)+1);
    auto factors = prime_factorization(primes, N);
    int64_t ans = 0;
    for(auto [f, cnt] : factors) {
        // 1 + 2 + 3 + .. <= cnt
        // n(n+1)/2 <= cnt
        auto max_n = find_maximum_solution(0, cnt, [cnt=cnt](int64_t n){
            return n * (n+1) <= 2 * cnt;
        });
        ans += max_n;
    }
    cout << ans << LF;
}


Measured memory_bytes: 3784