| # | Time | Username | Problem | Language | Result | Execution time | Memory | 
|---|---|---|---|---|---|---|---|
| 446658 | Kepha | Holiday (IOI14_holiday) | C++11 | 0 ms | 0 KiB | 
This submission is migrated from previous version of oj.uz, which used different machine for grading. This submission may have different result if resubmitted.
// IOI 2014 Day 2 Problem 3 holiday
#include <bits/stdc++.h>
#define int long long
#define MX 100000
#define pii pair<int, int>
using namespace std;
using namespace chrono;
struct SegTree{
    const int VALUE = 0;
    int size, n;
    vector<int> sums, active; // sums is [0...2*size-1]
    void init(int n) {
        size = 1;
        while (size < n) size *= 2;
        sums.assign(2 * size, VALUE);
        active.assign(2 * size, 0);
    }
    int query(int node, int x) {
        if (active[node] <= x) return sums[node];
        // if (node >= size) return sums[node];
        if (active[node * 2 + 1] > x)
            return query(node * 2 + 1, x);
        else if (active[node * 2 + 1] == x)
            return sums[node * 2 + 1];
        else return query(node * 2, x - active[node * 2 + 1]) + sums[node * 2 + 1];
    }
    // assumes pos is 1 - based
    void update(int pos, int value, int act) {
        if (pos == 0) return;
        pos += size - 1;
        sums[pos] = value;
        // do we activate?
        active[pos] = act;
        for (pos /= 2; pos >= 1; pos /= 2) {
            sums[pos] = sums[pos * 2] + sums[pos * 2 + 1];
            active[pos] = active[pos * 2] + active[pos * 2 + 1];
        }
    }
};
int N, start, d, NL, NR;
// sorted arrays
vector<pii> Left, Right;
// occ[i] = index after sorting
vector<int> occLeft, occRight;
// active range, based on indices of a single range
int curL = 0, curR = 0;
// g[i] = [1, start) when d = i, f[i] = [start, N] when d = i
vector<pii> f, g;
SegTree seg;
int Arr[MX + 1];
// need to take care of 0
// A is either Left/Right, occ is either occLeft/occRight
void activate(int L, int R, vector<pii> A, vector<int> occ) {
    while (curL > L) curL--, seg.update(occ[curL], A[occ[curL]].first, 1);
    while (curR < R) curR++, seg.update(occ[curR], A[occ[curR]].first, 1);
    while (curL < L) seg.update(occ[curL], 0, 0), curL++;
    while (curR > R) seg.update(occ[curR], 0, 0), curR--;
}
// pos, cnt
pii search(int l, int r, int curd, vector<pii> A, vector<int> occ) {
    activate(0, l - 1, A, occ);
    pii ans = {-1, -1};
    for (int i = l; i <= r; i++) {
        if (curd - i + 1 <= 0) break;
        seg.update(occ[i], A[occ[i]].first, 1);
        ++curR;
        int val = seg.query(1, curd - i + 1); // start at 1, so (i - 1)
        if (val > ans.second)
            ans = {i, val};
    }
    return ans;
}
// l, r here means d. optl, optr means positions to search
void dfs(int l, int r, int optl, int optr, 
        vector<pii> A, vector<int> occ, vector<pii>& V) {
    if (l > r) return;
    int mid = (l + r) / 2;
    V[mid] = search(optl, optr, mid, A, occ);
    int opt = V[mid].first;
    dfs(l, mid - 1, optl, opt, A, occ, V);
    dfs(mid + 1, r, opt, optr, A, occ, V);
}
signed main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> N >> start >> d;
    start++;
    NL = start - 1, NR = N - start + 1;
    Left.resize(NL + 1);
    occLeft.resize(NL + 1, 0);
    Right.resize(NR + 1);
    occRight.resize(NR + 1, 0);
    f.resize(d + 1);
    g.resize(d + 1);
    for (int i = 1; i <= N; i++) {
        int x; cin >> x; Arr[i] = x;
        if (i < start) Left[i] = {x, i};
        else Right[i - start + 1] = {x, i - start + 1};
    }
    sort(Left.begin() + 1, Left.begin() + 1 + NL);
    sort(Right.begin() + 1, Right.begin() + 1 + NR);
    for (int i = 1; i <= NL; i++)
        occLeft[Left[i].second] = i;
    for (int i = 1; i <= NR; i++)
        occRight[Right[i].second] = i;
    // g(), RIGHT PART
    seg.init(NR + 1);
    f[0] = {1, 0};
    if (NR > 0)
        dfs(1, d, 1, NR, Right, occRight, f);
    // f(), LEFT PART
    seg.init(NL + 1);
    // originally we traverse occLeft from start - 1 to 1, 
    // now we reverse the list and traverse from 1 to start - 1 
    reverse(occLeft.begin() + 1, occLeft.begin() + 1 + NL);
    curL = curR = 0;
    g[0] = {1, 0};
    if (NL > 0)
        dfs(1, d, 1, NL, Left, occLeft, g);
    // FINAL ANSWER
    int ans = 0;
    // go to right, then left
    for (int d0 = 0; d0 <= d; d0++) {
        int cnt = f[d0].second;
        int cost = d - d0 - (f[d0].first - 1) - 1;
        ans = max(ans, cnt);
        if (cost < 0) continue;
        cnt += g[cost].second;
        ans = max(ans, cnt);
    }
    // go to left, then right
    for (int d0 = 1; d0 <= d; d0++) {
        int cnt = g[d0 - 1].second;
        int cost = d - d0 - (g[d0 - 1].first - 1) - 1;
        ans = max(ans, cnt);
        if (cost < 0) continue;
        cnt += f[cost].second;
        ans = max(ans, cnt);
    }
    cout << ans << "\n";
    return 0;
}
