Karte

Neka je dat niz od \(n\) karata. Inicijalno, sve karte su okrenute licem dole. Postoje dva tipa upita:

Opis ulaza

Sa standardnog ulaza se učitavaju celi brojevi \(n\) i \(q\), a zatim i \(q\) upita. Svaki upit \(k=0,\ldots,q-1\) čini tip upita \(t_k \in \{0, 1\}\) i argumenti upita. Ukoliko je \(t_k = 0\), argumenti upita su \(l_k, r_k\) (\(0 \leq l_k, r_k < n\)), a ukoliko je \(t_k = 1\), argument upita je indeks \(i_k\) (\(0 \leq i_k < n\)).

Opis izlaza

Za svaki upit tipa \(1\) ispisati na standardni izlaz stanje karte koja se nalazi na odgovarajućoj poziciji.

Primer

Ulaz

5 8 0 1 2 0 1 4 0 0 0 1 2 1 3 0 0 4 1 2 1 3

Izlaz

0 1 1 0

Objašnjenje

0 1 2 3 4 --------- 0 0 0 0 0 0 1 2 --> 0 1 1 0 0 0 1 4 --> 0 0 0 1 1 0 0 0 --> 1 0 0 1 1 1 2 _ --> 0 1 3 _ --> 1 0 0 4 --> 0 1 1 0 0 1 2 _ --> 1 1 3 _ --> 0

Rešenje

Opis glavnog rešenja

Zadatak možemo rešiti naivno. U nizu \(a\) veličine \(n\) održavamo indikatore \(a_i\) (\(0 \leq i < n\)), pri čemu je \(a_i = 0\) ukoliko je karta na poziciji \(i\) okrenuta licem dole, a \(a_i = 1\) ukoliko je karta na poziciji \(i\) okrenuta licem gore. Niz \(a\) inicijalno popunimo nulama. Za upit prvog tipa, za svako \(i = l, \ldots, r\) ažuriramo \(a_i \gets \neg a_i\), dok za upit drugog tipa jednostavno ispišemo vrednost \(a_i\). Kod ovakvog pristupa za prvi tip upita vremenska složenost je \(O(n)\), dok je za drugi tip upita vremenska složenost \(O(1)\). Tada je ukupna složenost rešenja \(O(qn)\).

Bolje rešenje koristi niz \(f\) dužine \(n+1\). Inicijalno niz \(f\) popunimo nulama. Sa svaki upit prvog tipa uvećamo \(f_l\) za jedan i umanjimo \(f_{r + 1}\) za jedan. Tada važe sledeća tvrđenja:

Teorema 1: Nakon izvršavanja upita \(0 \, l \, r\), za svako \(k = l, \ldots, r\) važi da je prefiksna suma \(f_0 + f_1 + \ldots + f_k\) uvećana za jedan, dok će sve ostale prefiksne sume ostati iste. \(\blacksquare\)

Teorema 2: Ako je \(b_i\) broj okretanja karte na \(i\)-toj poziciji, onda je \(f_0 + f_1 + \ldots + f_i = b_i\), za svako \(i=0,\ldots,n-1\).

Dokaz: Fiksirajmo kartu na poziciji \(i\) i pokažimo tvrđenje indukcijom po broju izvršavanja upita prvog tipa.

Da bi odgovorili na drugi tip upita, zbog teoreme 2, jednostavno izračunamo prefiksnu sumu \(f_0 + f_1 + \ldots + f_i\) po modulu \(2\). Za efikasno ažuriranje i izračunavanje prefiksnih suma niz \(f\) implementiraćemo Fenvikovim stablom. Ukupna složenost ovakvog rešenja je \(O(q \log n)\).

#include <iostream>
#include <vector>
#include <cmath>

using namespace std;

int BIT_sum(const vector<int> &bit, int k) 
{
    k++; // offset 1 from 0
         
    int sum = 0;
    while (k > 0) {
        sum += bit[k];
        k -= k & -k; // k = f(k)
    }
    return sum;
}

void BIT_update(vector<int> &bit, int k, const int x) 
{
    k++; // offset 1 from 0
    
    while (k <= bit.size()) {
        bit[k] += x;
        k += k & -k;
    }
}

int main(void) 
{
    int n, q; cin >> n >> q;

    vector<int> f(n + 2);

    while (q--) {
        int t; cin >> t;

        if (t == 0) {
            int l, r; cin >> l >> r;
            BIT_update(f, l, 1);
            BIT_update(f, r + 1, -1);
        } else { // t == 1
            int i; cin >> i;
            cout << BIT_sum(f, i) % 2 << endl;
        }
    }

    return 0;
}