제출 #319362

#제출 시각아이디문제언어결과실행 시간메모리
319362rqiElection (BOI18_election)C++14
100 / 100
1638 ms61460 KiB
#include <bits/stdc++.h>
using namespace std;

typedef pair<int, int> pi;
typedef vector<int> vi;
typedef vector<pi> vpi;

#define mp make_pair
#define f first
#define s second
#define sz(x) (int)(x).size()
#define all(x) begin(x), end(x)
#define pb push_back
#define bk back()

const int MOD = 1000000007;

struct SegTree{
    const static int SZ = 524288;
    int mn[2*SZ];
    int lazy[2*SZ];
    void init(){
        for(int i = 1; i < 2*SZ; i++){
            mn[i] = 0;
            lazy[i] = 0;
        }
    }
    void pull(int ind){
        mn[ind] = min(mn[2*ind], mn[2*ind+1]);
    }
    void push(int ind){
        mn[ind]+=lazy[ind];
        if(ind < SZ){
            lazy[2*ind]+=lazy[ind];
            lazy[2*ind+1]+=lazy[ind];
        }
        lazy[ind] = 0;
    }
    void upd(int lo, int hi, int val, int ind = 1, int L = 0, int R = SZ-1){
        push(ind);
        if(R < lo || L > hi) return;
        
        if(lo <= L && R <= hi){
            lazy[ind]+=val;
            push(ind);
            //cout << ind << " " << L << " " << R << " " << mn[ind] << "\n";
            return;
        }

        int M = (L+R)/2;

        upd(lo, hi, val, 2*ind, L, M);
        upd(lo, hi, val, 2*ind+1, M+1, R);

        pull(ind);
    }
    int query(int lo, int hi, int ind = 1, int L = 0, int R = SZ-1){
        push(ind);
        if(R < lo || L > hi) return MOD;
        
        if(lo <= L && R <= hi){
            // cout << "L,R,mn: " << L << " " << R << " " << mn[ind] << " " << lazy[ind] << "\n";
            // if(ind < SZ){
            //  cout << mn[2*ind] << " " << lazy[2*ind] << "\n";
            // }
            return mn[ind];
        }

        int M = (L+R)/2;

        int Q1 = query(lo, hi, 2*ind, L, M);
        int Q2 = query(lo, hi, 2*ind+1, M+1, R);

        return min(Q1, Q2);
    }
};

const int mx = 500005;

int bt[mx]; //keep track of removed stuff
void upd(int ind, int val){
    assert(1 <= ind && ind < mx);
    while(ind < mx){
        bt[ind]+=val;
        ind+=ind&-ind;
    }
}

int sum(int ind){
    assert(0 <= ind && ind < mx);
    if(ind == 0) return 0;
    int res = 0;
    while(ind > 0){
        res+=bt[ind];
        ind-=ind&-ind;
    }
    return res;
}

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

int N;
string votes;
int Q;
int L[mx];
int R[mx];
int ans[mx];
SegTree seg;

int pref[mx];

vi npos[2*mx]; //positions of x+1 --> x, shifted by mx. back is current

void INSERT(int ind){ //removing T at position ind
    //cout << "INSERT " << ind << "\n";
    upd(ind, 1);
    seg.upd(1, ind, 1);
}

int QUERY(int l, int r){
    //cout << "QUERY: " << l << " " << r << "\n";
    int ans = query(l, r);
    //cout << "origans: " << ans << "\n";
    int ival = seg.query(r+1, r+1);
    int mval = seg.query(l, r+1);

    //if(l == 4 && r == 9){
        // for(int i = 1; i <= 12; i++){
        //  cout << seg.query(i, i) << " ";
        // }
        // cout << "\n";
        //cout << ival << " " << mval << "\n";
    //}

    return ans+ival-mval;
}

int main(){
    cin >> N;
    cin >> votes;
    votes = "?" + votes;
    cin >> Q;
    for(int i = 1; i <= Q; i++){
        cin >> L[i] >> R[i];
    }
    seg.init();
    vpi queries;
    for(int i = 1; i <= Q; i++){
        queries.pb(mp(L[i], i));
    }
    sort(all(queries));

    pref[1] = 0;
    for(int i = 2; i <= N+1; i++){
        pref[i] = pref[i-1];
        if(votes[i-1] == 'C'){
            pref[i]++;
        }
        else{
            pref[i]--;
        }
    }

    for(int i = N; i >= 1; i--){
        if(votes[i] == 'T'){
            //cout << "i, pref[i+1] " << i << " " << pref[i+1] << "\n";
            npos[pref[i+1]+mx].pb(i);
        }
    }

    for(int i = -1; i >= -N; i--){
        if(sz(npos[i+mx])){
            //cout << i << " " << npos[i+mx].bk << "\n";
            INSERT(npos[i+mx].bk);
        }
    }

    int cursum = 0;
    for(int i = N+1; i >= 1; i--){
        if(i != N+1){
            if(votes[i] == 'C'){
                cursum++;
            }
            else if(votes[i] == 'T'){
                cursum--;
            }
        }
        seg.upd(i, i, cursum);
    }



    int curL = 1;
    
    for(int q = 0; q < Q; q++){
        int qind = queries[q].s;

        //cout << "qind: " << qind << "\n";

        while(curL < L[qind]){
            if(votes[curL] == 'C'){
                if(sz(npos[pref[curL+1]-1+mx])){
                    INSERT(npos[pref[curL+1]-1+mx].bk);
                }
            }
            else if(votes[curL] == 'T'){
                npos[pref[curL+1]+mx].pop_back();
                //ERASE(npos[pref[curL]+mx].bk); doesn't seem necessary?
            }
            curL++;
        }

        ans[qind] = QUERY(L[qind], R[qind]);
    }

    for(int i = 1; i <= Q; i++){
        cout << ans[i] << "\n";
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...