Submission #1106100

#TimeUsernameProblemLanguageResultExecution timeMemory
1106100ThunnusStreet Lamps (APIO19_street_lamps)C++17
20 / 100
904 ms115696 KiB
/*
- Maintain a set of maximal segments of contiguous ones.
- Whenever a segment is removed, create a point (a, b, -t).
- Whenever a segment is added, create a point (a, b, +t).
- Now for each query (aq, bq, tq), count the number of points (a, b, t)
  such that a < aq , b > bq , t < tq (we don't take credit of equal elements because the given input is one-based)
- Find the total sum of t, and the number of negative and positive events.
- If one positive event is missing, add 't' into the total sum.
- This can be easily solved with CDQ divide and conquer.
- My previous idea was using a 2D sparse segment tree to do the same,
  but it uses too much memory. Alas, the remnants of my code were still there,
  so i decided to reuse the 1D version instead of creating a new code for a
  regular segment tree. 
*/
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define int i64
#define vi vector<int>
#define vvi vector<vi>
#define vb vector<bool>
#define pii pair<int, int>
#define fi first
#define se second
#define sz(x) (int)(x).size()

const int MX = 3e5 + 5;

pii operator +(const pii &a, const pii &b){
    return {a.fi + b.fi, a.se + b.se};
}

pii operator -(const pii &a, const pii &b){
    return {a.fi - b.fi, a.se - b.se};
}

struct BIT{
    vector<pii> bit;
    BIT(int n) : bit(n + 1) {}

    inline void add(int idx, pii val){
        for(++idx; idx < sz(bit); idx += idx & -idx){
            bit[idx] = bit[idx] + val;
        }
        return;
    }

    inline pii query(int idx){
        pii ret = {0, 0};
        for(++idx; idx; idx -= idx & -idx){
            ret = ret + bit[idx];
        }
        return ret;
    }

    inline pii query(int l, int r){
        return query(r) - query(l - 1);
    }
};

vector<array<int, 5>> updates;
vector<pii> onans, offans;
BIT on(MX), off(MX);

inline void cdq(int l, int r){
    if(l + 1 == r) return;
    int m = (l + r) / 2;
    cdq(l, m); cdq(m, r);

    vector<pair<int, pii>> offrec, onrec;
    vector<array<int, 5>> temp;
    int a = l, b = m;
    while(a < m || b < r){
        bool left;
        int cur;
        if(a >= m || (b < r && updates[b][1] <= updates[a][1])) cur = b++, left = false;
        else cur = a++, left = true;
        temp.emplace_back(updates[cur]);

        if(left && updates[cur][3] == -1){
            off.add(updates[cur][2], {updates[cur][0], 1});
            offrec.push_back({updates[cur][2], {-updates[cur][0], -1}});
        }
        else if(left && updates[cur][3] == 1){
            on.add(updates[cur][2], {updates[cur][0], 1});
            onrec.push_back({updates[cur][2], {-updates[cur][0], -1}});
        }
        else if(!left && !updates[cur][3]){
            pii onval = on.query(updates[cur][2] + 1, MX - 1), offval = off.query(updates[cur][2] + 1, MX - 1);
            onans[updates[cur][4]] = onans[updates[cur][4]] + onval, offans[updates[cur][4]] = offans[updates[cur][4]] + offval;
        }
    }

    for(int i = 0; i < sz(offrec); i++){
        off.add(offrec[i].fi, offrec[i].se);
    }
    for(int i = 0; i < sz(onrec); i++){
        on.add(onrec[i].fi, onrec[i].se);
    }
    for(int i = l; i < r; i++){
        updates[i] = temp[i - l];
    }
    temp.clear(), offrec.clear(), onrec.clear();
    return;
}

signed main(){
    ios_base::sync_with_stdio(false); cin.tie(0);
    int n, q;
    string s, type;
    cin >> n >> q >> s;
    set<pii> seg;
    for(int i = 0; i < n; i++){
        if(s[i] == '1'){
            int l = i;
            while(i + 1 < n && s[i + 1] == '1') i++;
            seg.emplace(l, i);
            updates.push_back({0, l, i, 1});
        }
    }

    int qc = 0;
    vi qtime;
    for(int t = 1; t <= q; t++){
        cin >> type;
        if(type == "toggle"){
            int i;
            cin >> i;
            if(s[--i] == '0'){
                int l = i, r = i;
                auto right = seg.lower_bound({i, i});
                if(right != seg.end() && right->fi == i + 1){
                    r = right->se;
                    updates.push_back({t, i + 1, r, -1});
                    seg.erase(right);
                }

                auto left = seg.lower_bound({i, i});
                if(left != seg.begin()) left--;
                if(left != seg.end() && left->se == i - 1){
                    l = left->fi;
                    updates.push_back({t, l, i - 1, -1});
                    seg.erase(left);
                }
                seg.emplace(l, r);
                updates.push_back({t, l, r, 1});
                s[i] = '1';
            }
            else{
                auto it = prev(seg.lower_bound({i + 1, i + 1}));
                int l = it->fi, r = it->se;
                updates.push_back({t, l, r, -1});
                if(l < i){
                    updates.push_back({t, l, i - 1, 1});
                    seg.emplace(l, i - 1);
                }
                if(r > i){
                    updates.push_back({t, i + 1, r, 1});
                    seg.emplace(i + 1, r);
                }
                s[i] = '0';
            }
        }
        else{
            int ql, qr;
            cin >> ql >> qr;
            updates.push_back({t, ql, qr - 3, 0, qc++}); // qr - 3 ?
            qtime.emplace_back(t);
        }
    }
    sort(updates.begin(), updates.end());
    onans.resize(qc), offans.resize(qc);

    cdq(0, sz(updates));
    for(int i = 0; i < qc; i++){
        int ans = offans[i].fi - onans[i].fi;
        if(onans[i].se > offans[i].se) ans += qtime[i];
        cout << ans << "\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...
#Verdict Execution timeMemoryGrader output
Fetching results...