mayoko’s diary

プロコンとかいろいろ。

square869120Contest #2 H - Counting 1's

解法

遅延評価セグメント木で解きました。

update で [l, r) の区間を反転させ, query で [l, r) の 1 の数を求めるような機能を実現します。

lazy 配列には「今考えている区間は後で反転させるつもりか」というのを覚えておきます。後はコード見ましょう。

// 遅延評価つきセグメント木
// update: [l, r) の区間を反転させる
// query:  [l, r) の 1 の数の和を求める
// lazy を反転フラグにすればユーテイケルッショ
struct ST {
    vector<int> seg, lazy;
    int size;

    ST(int n) {
        size = 1;
        while (size < n) size *= 2;
        seg.resize(size * 2);
        lazy.resize(size * 2);
    }

    inline void push(int k, int l, int r) {
        if (lazy[k] != 0) {
            seg[k] = (r-l)-seg[k];
            if (r - l > 1) {
                lazy[k * 2 + 1] ^= lazy[k];
                lazy[k * 2 + 2] ^= lazy[k];
            }
            lazy[k] = 0;
        }
    }

    inline int merge(int x, int y) {
        return x + y;
    }

    void update(int a, int b, int k, int l, int r) {
        push(k, l, r);
        if (r <= a || b <= l) return;
        if (a <= l && r <= b) {
            lazy[k] = 1;
            push(k, l, r);
        } else {
            update(a, b, k * 2 + 1, l, (l + r) / 2);
            update(a, b, k * 2 + 2, (l + r) / 2, r);
            seg[k] = merge(seg[k * 2 + 1], seg[k * 2 + 2]);
        }
    }

    void update(int a, int b) {
        return update(a, b, 0, 0, size);
    }

    int query(int a, int b, int k, int l, int r) {
        push(k, l, r);
        if (r <= a || b <= l) return 0;
        if (a <= l && r <= b) return seg[k];
        int x = query(a, b, k * 2 + 1, l, (l + r) / 2);
        int y = query(a, b, k * 2 + 2, (l + r) / 2, r);
        return merge(x, y);
    }

    ll query(int a, int b) {
        return query(a, b, 0, 0, size);
    }
};

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, Q;
    cin >> n >> Q;
    ST seg(n);
    while (Q--) {
        int q, l, r;
        cin >> q >> l >> r;
        if (q==1) {
            seg.update(l, r);
        } else {
            cout << seg.query(l, r) << endl;
        }
    }
    return 0;
}