Submission #1263391

#TimeUsernameProblemLanguageResultExecution timeMemory
1263391niepamietamhaslaMixture (BOI20_mixture)C++20
100 / 100
322 ms47460 KiB
#include <bits/stdc++.h>
using namespace std;

// Use __int128 for all heavy arithmetic
typedef __int128 i128;
typedef long long ll; // keep for reading q/counters from stdin

// array size
const int MAXN = 100000 + 5;

struct d {
    i128 a;
    i128 b;
    i128 S;
};

d pts[MAXN];
d cel;

//
// gcd for __int128
//
i128 gcd128(i128 a, i128 b) {
    if (a < 0) a = -a;
    if (b < 0) b = -b;
    while (b != 0) {
        i128 r = a % b;
        a = b;
        b = r;
    }
    return a >= 0 ? a : -a;
}

d przemien(i128 a, i128 b, i128 c) {
    i128 S = a + b + c;
    i128 G = gcd128(a, gcd128(b, S));
    if (G == 0) return {0,0,0};
    return {a / G, b / G, S / G};
}

void wypisztrojke(d u){
    // debug printing of __int128 (disabled by default)
    // auto print128 = [](i128 x){
    //     if(x==0){ cout<<"0"; return; }
    //     bool neg = x < 0;
    //     if(neg) x = -x;
    //     string s;
    //     while(x > 0){
    //         int digit = int(x % 10);
    //         s.push_back(char('0' + digit));
    //         x /= 10;
    //     }
    //     if(neg) cout << "-";
    //     reverse(s.begin(), s.end());
    //     cout << s;
    // };
    // cout << "("; print128(u.b); cout << ", "; print128(u.a); cout << ")   para\n";
}

struct comp {
    bool operator()(const d &d1, const d &d2) const {
        if (d1.a != d2.a) return d1.a < d2.a;
        if (d1.b != d2.b) return d1.b < d2.b;
        if (d1.S != d2.S) return d1.S < d2.S;
        return false;
    }
};

// maps and counters (use __int128 for numeric values)
map<d, i128, comp> ile;
map<d, i128, comp> M;
typedef pair<i128, i128> pii128;
map<pii128, i128> nad;
map<pii128, i128> pod;

i128 lewozero = 0;
i128 prawozero = 0;
i128 ilewiekszych = 0;
i128 ileprostych = 0;

//
// convexity / orientation using __int128
//
int wypuklosc(const d &d1, const d &d2, const d &d3) {
    // returns -1,0,1
    i128 v = d3.a * d1.b - d1.a * d3.b;
    if (v < 0) return -1;
    if (v > 0) return 1;
    return 0;
}

struct comp2 {
    bool operator()(const d &d1, const d &d2) const {
        bool up1 = (d1.a > 0) || (d1.a == 0 && d1.b > 0);
        bool up2 = (d2.a > 0) || (d2.a == 0 && d2.b > 0);
        if (up1 != up2) return up1;

        int o = wypuklosc(d1, {0,0,1}, d2);
        if (o != 0) return o > 0;

        if (d1.a != d2.a) return d1.a * d2.S < d2.a * d1.S;
        if (d1.b != d2.b) return d1.b * d2.S < d2.b * d1.S;
        return d1.S < d2.S;
    }
};

multiset<d, comp2> proste;

int wypuklosc2(const d &d1, const d &d2, const d &d3) {
    // similar logic as original, adapted to __int128
    i128 v = d3.a * d1.b - d1.a * d3.b;
    if (v < 0) return -1;
    if (v > 0) return 1;

    if (d1.a == 0 && d3.a == 0) return 1;
    if ((d1.a > 0 && d3.a < 0) || (d1.a < 0 && d3.a > 0)) return 1;

    auto it = proste.lower_bound(d1);
    ++it;
    if (it == proste.end()) {
        return -1;
    } else {
        return 1;
    }
}

bool c1 = false, c2 = false, c3 = false;

void dodajprosta(d punkt) {
    if (proste.size() < 2) {
        if (proste.size() == 0) ilewiekszych = 1;
        else {
            if (c2) ilewiekszych = 0;
            else ilewiekszych = 1;
        }
        proste.insert(punkt);
        return;
    }

    auto nxt = proste.lower_bound(punkt);
    if (nxt == proste.end()) nxt = proste.begin();

    auto prev = nxt;
    if (prev == proste.begin()) {
        prev = --(proste.end());
    } else {
        --prev;
    }

    if (wypuklosc2(*prev, {0,0,1}, *nxt) == -1) {
        ilewiekszych--;
    }

    proste.insert(punkt);

    if (wypuklosc2(*prev, {0,0,1}, punkt) == -1) ilewiekszych++;
    if (wypuklosc2(punkt, {0,0,1}, *nxt) == -1) ilewiekszych++;

    return;
}

void usunprosta(d punkt) {
    if (proste.size() <= 3) {
        if (proste.size() == 3) {
            if (c2) ilewiekszych = 0;
            else ilewiekszych = 1;
        } else if (proste.size() == 2) ilewiekszych = 1;
        else ilewiekszych = 0;
        auto it = proste.find(punkt);
        if (it != proste.end()) proste.erase(it);
        return;
    }

    auto x = proste.find(punkt);
    if (x == proste.end()) return; // nothing to erase

    auto prev = x;
    if (prev == proste.begin()) prev = --(proste.end());
    else --prev;

    auto nxt = x;
    ++nxt;
    if (nxt == proste.end()) nxt = proste.begin();

    if (wypuklosc2(*prev, {0,0,1}, punkt) == -1) ilewiekszych--;
    if (wypuklosc2(punkt, {0,0,1}, *nxt) == -1) ilewiekszych--;

    auto it = proste.find(punkt);
    if (it != proste.end()) proste.erase(it);

    if (wypuklosc2(*prev, {0,0,1}, *nxt) == -1) ilewiekszych++;

    return;
}

void dodaj(d punkt) {
    if (ile[punkt] > 0) {
        ile[punkt]++;
        return;
    }
    ile[punkt]++;

    M[punkt]++;

    if (M[{0,0,1}] > 0) c1 = true;
    if (punkt.a == 0 && punkt.b == 0) return;

    if (punkt.a == 0) {
        if (punkt.b < 0) {
            lewozero++;
            if (lewozero > 0 && prawozero > 0) c2 = true;
        } else {
            prawozero++;
            if (lewozero > 0 && prawozero > 0) c2 = true;
        }
    } else if ((punkt.a < 0 && punkt.S < 0) || (punkt.a > 0 && punkt.S > 0)) {
        i128 G = gcd128(punkt.a, punkt.b);
        pii128 x = {punkt.a / G, punkt.b / G};
        nad[x]++;
        if (nad[x] == 1 && pod[x] > 0) ileprostych++;
    } else {
        i128 G = gcd128(punkt.a, punkt.b);
        pii128 x = {punkt.a / G, punkt.b / G};
        x.first = -x.first;
        x.second = -x.second;
        pod[x]++;
        if (pod[x] == 1 && nad[x] > 0) ileprostych++;
    }

    if (ileprostych > 0 || (lewozero > 0 && prawozero > 0)) c2 = true;
    else c2 = false;

    dodajprosta(punkt);

    if (ilewiekszych <= 0 && proste.size() > 2) c3 = true;
    else c3 = false;
}

void usun(d punkt) {
    if (ile[punkt] > 1) {
        ile[punkt]--;
        return;
    }
    ile[punkt]--;
    M[punkt]--;
    if (M[{0,0,1}] == 0) c1 = false;
    if (punkt.a == 0 && punkt.b == 0) return;

    if (punkt.a == 0) {
        if (punkt.b < 0) {
            lewozero--;
            if (lewozero == 0 || prawozero == 0) c2 = false;
        } else {
            prawozero--;
            if (lewozero == 0 || prawozero == 0) c2 = false;
        }
    } else if ((punkt.a < 0 && punkt.S < 0) || (punkt.a > 0 && punkt.S > 0)) {
        i128 G = gcd128(punkt.a, punkt.b);
        pii128 x = {punkt.a / G, punkt.b / G};
        bool c = (pod[x] > 0 && nad[x] > 0);
        nad[x]--;
        if (c && (pod[x] == 0 || nad[x] == 0)) ileprostych--;
    } else {
        i128 G = gcd128(punkt.a, punkt.b);
        pii128 x = {punkt.a / G, punkt.b / G};
        x.first = -x.first; x.second = -x.second;
        bool c = (pod[x] > 0 && nad[x] > 0);
        pod[x]--;
        if (c && (pod[x] == 0 || nad[x] == 0)) ileprostych--;
    }

    if (ileprostych > 0 || (lewozero > 0 && prawozero > 0)) c2 = true;
    else c2 = false;

    usunprosta(punkt);

    if (ilewiekszych <= 0 && proste.size() > 2) c3 = true;
    else c3 = false;
}

// helper to safely convert small __int128 to int for printing (0..3)
int i128_to_int(i128 x) {
    long long t = (long long)x;
    return (int)t;
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    // Read initial triple (use ll for reading to preserve cin behaviour)
    ll a_, b_, c_;
    if (!(cin >> a_ >> b_ >> c_)) return 0;
    i128 a = (i128)a_;
    i128 b = (i128)b_;
    i128 c = (i128)c_;

    cel = przemien(a, b, c);

    ll q;
    cin >> q;
    char x;
    int cnt = 1;
    for (ll i = 0; i < q; ++i) {
        cin >> x;
        if (x == 'A') {
            cin >> a_ >> b_ >> c_;
            i128 aa = (i128)a_;
            i128 bb = (i128)b_;
            i128 cc = (i128)c_;
            i128 TMP = gcd128(aa, gcd128(bb, cc));
            if (TMP != 0) { aa /= TMP; bb /= TMP; cc /= TMP; }
            pts[cnt] = przemien(aa, bb, cc);

            d nowy;
            nowy.a = pts[cnt].a * cel.S - cel.a * pts[cnt].S;
            nowy.b = pts[cnt].b * cel.S - cel.b * pts[cnt].S;
            nowy.S = cel.S * pts[cnt].S;
            if (nowy.a == 0 && nowy.b == 0) nowy.S = 1;
            i128 G = gcd128(nowy.a, gcd128(nowy.b, nowy.S));
            if (G != 0) { nowy.a /= G; nowy.b /= G; nowy.S /= G; }

            pts[cnt] = nowy;
            // wypisztrojke(pts[cnt]); // debug
            dodaj(pts[cnt]);
            cnt++;
        } else {
            ll idx;
            cin >> idx;
            if (idx >= 0 && idx < MAXN) {
                // debug: wypisztrojke(pts[idx]);
                usun(pts[idx]);
                pts[idx] = {0,0,0};
            } else {
                // out-of-range (shouldn't happen given original code assumptions)
            }
        }

        int out = c1 ? 1 : (c2 ? 2 : (c3 ? 3 : 0));
        cout << out << '\n';
    }

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