Submission #1370646

#TimeUsernameProblemLanguageResultExecution timeMemory
1370646chithanhnguyenFortune Telling 2 (JOI14_fortune_telling2)C++20
100 / 100
243 ms23264 KiB
/*
Author: Nguyen Chi Thanh - High School for the Gifted - VNU.HCM (i2528)
*/
#include <bits/stdc++.h>
using namespace std;

/* START OF TEMPALTE */

// #define int long long
#define ll long long
#define ull unsigned long long
#define ld long double
#define pii pair<int, int>
#define pll pair<ll, ll>
#define fi first
#define se second
#define popcount __builtin_popcountll
#define all(x) (x).begin(), (x).end()
#define BIT(x, i) (((x) >> (i)) & 1)
#define MASK(x) (1ll << (x))
#define SZ(a) ((int32_t)a.size())

#define debug(a, l, r) {for (int _i = (l); _i <= (r); ++_i) cout << (a)[_i] << ' '; cout << '\n';}

template<class X, class Y>
bool minimize(X &x, const Y &y) {
    if (x > y) {
        x = y;
        return true;
    } else return false;
}

template<class X, class Y>
bool maximize(X &x, const Y &y) {
    if (x < y) {
        x = y;
        return true;
    } else return false;
}

/* END OF TEMPALTE */

const int MAXN = 2e5 + 5;

struct SegmentTreeMax {
    int n;
    vector<int> seg;

    SegmentTreeMax() {}
    SegmentTreeMax(int _n) : n(_n), seg(4 * n + 5, 0) {}
    void init(int _n) {*this = SegmentTreeMax(_n);}

    void update(int id, int l, int r, int pos, int val) {
        if (pos < l || pos > r) return;
        if (l == r) {
            maximize(seg[id], val);
            return;
        }

        int mid = (l + r) >> 1;
        update(id << 1, l, mid, pos, val);
        update(id << 1 | 1, mid + 1, r, pos, val);

        seg[id] = max(seg[id << 1], seg[id << 1 | 1]);
    }

    int get(int id, int l, int r, int u, int v) {
        if (v < l || r < u) return 0;
        if (u <= l && r <= v) return seg[id];

        int mid = (l + r) >> 1;
        int getLeft = get(id << 1, l, mid, u, v);
        int getRight = get(id << 1 | 1, mid + 1, r, u, v);

        return max(getLeft, getRight);
    }

    void update(int pos, int val) {update(1, 1, n, pos, val);}
    int get(int u, int v) {
        if (u > v) return 0;
        return get(1, 1, n, u, v);
    }
};

struct FenwickTree {
    int n;
    vector<int> fen;

    FenwickTree() {}
    FenwickTree(int _n) : n(_n), fen(n + 5) {}
    void init(int _n) {*this = FenwickTree(_n);}

    void update(int idx, int v) {
        assert(idx > 0);
        for (int i = idx; i <= n; i += i & -i)
            fen[i] += v;
    }

    int get(int idx) {
        int sum = 0;
        for (int i = idx; i; i -= i & -i)
            sum += fen[i];
        return sum;
    }

    int query(int l, int r) {
        if (l > r) return 0;
        return get(r) - get(l - 1);
    }
};

struct Normalize {
    vector<int> vals;

    void add(int v) {vals.push_back(v);}
    void build() {
        sort(all(vals));
        vals.erase(unique(all(vals)), end(vals));
    }

    int get(int v) {
        return (int)(lower_bound(all(vals), v) - begin(vals)) + 1;
    }

    void compress(int &v) {v = get(v);}
    int size() {return SZ(vals);}

    int restore(int v) {
        return vals[v - 1];
    }
};

struct Card {
    int upside, downside;

    Card (int a = 0, int b = 0) : upside(a), downside(b) {}
    void output() {cout << upside << ' ' << downside << '\n';}
};

// How many number >= x in range [l, r]
struct Query {
    int l, r, x, id;

    bool operator < (const Query &other) const {
        return x > other.x;
    }

    void output() {
        cout << "Query [" << l << ", " << r << "], x = " << x << ", id = " << id << "\n";
    }
};

int n, q, operation[MAXN], lastPos[MAXN], numChanged[MAXN];
Card cards[MAXN];
Normalize comp;
SegmentTreeMax seg;
FenwickTree fen;

void init() {
    cin >> n >> q;

    for (int i = 1; i <= n; ++i) {
        int a, b; cin >> a >> b;
        cards[i] = {a, b};
        comp.add(a); comp.add(b);
    }

    for (int i = 1; i <= q; ++i) {
        int x; cin >> x;
        operation[i] = x; comp.add(x);
    }

    comp.build();

    for (int i = 1; i <= n; ++i) {
        comp.compress(cards[i].upside);
        comp.compress(cards[i].downside);
    }

    for (int i = 1; i <= q; ++i) comp.compress(operation[i]);

    // for (int i = 1; i <= n; ++i) cards[i].output();
    // debug(operation, 1, q);
}

void solve() {
    seg.init(comp.size() + 5);
    fen.init(q + 5);
    for (int i = 1; i <= q; ++i)
        seg.update(operation[i], i);

    for (int i = 1; i <= n; ++i) {
        int l = cards[i].upside, r = cards[i].downside;
        if (l > r) swap(l, r);
        lastPos[i] = seg.get(l, r - 1);
    }

    // debug(lastPos, 1, n);  

    vector<Query> queries;
    for (int i = 1; i <= n; ++i) {
        if (lastPos[i] >= q) continue;
        int target = max(cards[i].upside, cards[i].downside);
        queries.push_back({lastPos[i] + 1, q, target, i});
    }

    sort(all(queries));

    vector<pii> vals;
    for (int i = 1; i <= q; ++i) 
        vals.push_back({operation[i], i});
    sort(all(vals), greater<pii>());

    int ptr = 0;
    for (auto &qry : queries) {
        while (ptr < q && vals[ptr].fi >= qry.x) {
            fen.update(vals[ptr].se, 1);
            ++ptr;
        }

        int cnt = fen.query(qry.l, qry.r);
        numChanged[qry.id] = cnt;
    }

    // debug(numChanged, 1, n);

    ll ans = 0;
    for (int i = 1; i <= n; ++i) {
        vector<int> face(2);
        face[0] = cards[i].upside; face[1] = cards[i].downside;
        if (lastPos[i] > 0 && face[0] < face[1])
            swap(face[0], face[1]);
        
        int original = comp.restore(face[numChanged[i] & 1]);
        ans += (ll)original;
    }

    cout << ans;
}

signed main() {
    #ifdef NCTHANH
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif
    ios_base::sync_with_stdio(0);
    cin.tie(nullptr); cout.tie(nullptr);

    init();
    solve();

    return 0;
}
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...
#Result Execution timeMemoryGrader output
Fetching results...