Submission #996924

#TimeUsernameProblemLanguageResultExecution timeMemory
996924caterpillowDancing Elephants (IOI11_elephants)C++17
100 / 100
2001 ms79996 KiB
#include <bits/stdc++.h>
#include "elephants.h"

using namespace std;

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")

using ll = long long;
using pl = pair<ll, ll>;
using pi = pair<int, int>;
#define vt vector
#define f first
#define s second
#define pb push_back
#define all(x) x.begin(), x.end() 
#define size(x) ((int) (x).size())
#define FOR(i, a, b) for (int i = (a); i < (b); i++)
#define ROF(i, a, b) for (int i = (b) - 1; i >= (a); i--)
#define F0R(i, b) FOR (i, 0, b)
#define endl '\n'
const ll INF = 1e18;
const int inf = 1e9;

random_device rd;
mt19937 mt(rd());

using ptr = struct Node*;
struct Node {
    int pri, sz, val, agg, lazy;
    ptr l, r, par;

    Node (int _v) {
        pri = mt();
        sz = 1;
        l = r = par = 0;
        val = agg = _v;
        lazy = 0;
    }
};

inline int sz(ptr n) { return n ? n->sz : 0; }
inline int agg(ptr n) { return n ? n->agg : -1; }

void push(ptr n) {
    if (!n) return;
    n->val += n->lazy;
    n->agg += n->lazy;
    if (n->l) n->l->lazy += n->lazy;
    if (n->r) n->r->lazy += n->lazy;
    n->lazy = 0;
}

ptr pull(ptr n) {
    if (!n) return n;
    push(n->l), push(n->r);
    n->sz = sz(n->l) + 1 + sz(n->r);
    n->agg = max({agg(n->l), n->val, agg(n->r)});
    if (n->l) n->l->par = n;
    if (n->r) n->r->par = n;
    return n;
}

pair<ptr, ptr> spliti(ptr n, int i) {
    if (!n) return {n, n};
    push(n);
    n->par = 0;
    if (i <= sz(n->l)) {
        auto [l, r] = spliti(n->l, i);
        n->l = r;
        return {l, pull(n)};
    } else {
        auto [l, r] = spliti(n->r, i - sz(n->l) - 1);
        n->r = l;
        return {pull(n), r};
    }
}

tuple<ptr, ptr, ptr> cut(ptr n, int lo, int hi) {
    auto [lhs, r] = spliti(n, hi + 1);
    auto [l, m] = spliti(lhs, lo);
    return {l, m, r};
}

ptr merge(ptr l, ptr r) {
    if (!l || !r) return l ? l : r;
    push(l), push(r);
    ptr t;
    if (l->pri > r->pri) l->r = merge(l->r, r), t = l;
    else r->l = merge(l, r->l), t = r;
    return pull(t);
}

void add(ptr n, int v) {
    if (!n) return;
    n->lazy += v;
    push(n);
}

int order(ptr n, ptr from = 0) {
    if (!n) return -1; // hack
    int res = order(n->par, n);
    if (from == n->r || !from) res += sz(n->l) + 1;
    return res;
}

void clean(ptr n) {
    if (!n) return;
    clean(n->par);
    push(n);
}

ll n, w;
set<pl> cows;
vt<ll> pos;
vt<pair<ptr, ptr>> loc; // {in, out}
ptr tour;

void erase(int u) {
    int in = order(loc[u].f);
    int out = order(loc[u].s);
    auto [l, mid, r] = cut(tour, in, out);
    auto [ml, m, mr] = cut(mid, 1, sz(mid) - 2);
    push(ml);
    add(m, -(ml->val) - 1);
    tour = merge(l, r);
    cows.erase({pos[u], u});
    auto it = cows.lower_bound({pos[u], -INF});
    int p = it->s;
    clean(loc[p].f);
    add(m, loc[p].f->val + 1);
    auto [lhs, rhs] = spliti(tour, order(loc[p].f) + 1);
    tour = merge(lhs, merge(m, rhs));
}

void insert(int u, ll x) {
    pos[u] = x;
    auto pit = prev(cows.lower_bound({x, -INF}));
    auto it = cows.lower_bound({pit->f - w, -INF});
    auto eit = cows.lower_bound({x - w, -INF});
    ptr mid = 0;
    auto cit = cows.lower_bound({x, -INF});
    if (it->f < eit->f && ((cit->f == x && cit->s > u) || cit->f > x)) {
        int in = order(loc[it->s].f);
        int out = order(loc[prev(eit)->s].s);
        ptr l, r;
        tie(l, mid, r) = cut(tour, in, out);
        tour = merge(l, r);
        int op = cit->s; // original parent
        clean(loc[op].f);
        add(mid, -loc[op].f->val - 1);
    }
    pit = cows.upper_bound({x + w, INF});
    int p = pit->s;
    clean(loc[p].f);
    int rd = loc[p].f->val + 1;
    add(mid, rd + 1);
    auto inn = new Node(rd);
    auto outn = new Node(rd);
    mid = merge(inn, merge(mid, outn));
    loc[u] = {inn, outn};
    auto nxt = cows.lower_bound({x, u});
    int si;
    if (nxt->f + w < pos[p]) si = order(loc[nxt->s].f); // before next child
    else si = order(loc[p].s); // end of children
    auto [lhs, rhs] = spliti(tour, si);
    tour = merge(lhs, merge(mid, rhs));
    cows.insert({x, u});
}

void build(int u, int d = 0) {
    ptr in = new Node(d);
    tour = merge(tour, in);
    loc[u].f = in;
    if (cows.lower_bound({pos[u], -INF})->s == u && pos[u] != -INF) {
        auto pit = prev(cows.lower_bound({pos[u], -INF}));
        auto it = cows.lower_bound({pit->f - w, -INF});
        auto eit = cows.lower_bound({pos[u] - w, -INF});
        while (it != eit) {
            build(it->s, d + 1);
            it++;
        }
    }
    ptr out = new Node(d);
    tour = merge(tour, out);
    loc[u].s = out;
}

void init(int N, int L, int X[]) {
    n = N + 2;
    w = L;
    pos.resize(n);
    loc.resize(n);
    F0R (i, n - 2) pos[i + 1] = X[i];
    pos[0] = -INF;
    pos[n - 1] = INF;
    F0R (i, n) cows.insert({pos[i], i});
    build(n - 1);
}

int update(int u, int y) {
    u++;
    erase(u);
    insert(u, y);
    push(tour);
    return agg(tour) - 1;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...