Codeforces Round #149 (Div. 2 only) (No. 242) 本番

http://codeforces.com/contest/242

Coding

A

やるだけ

B

やるだけ

C

ダイクストラするだけ。
でも割と慣れてないから、色々バグらせたりでそれなりに時間が掛かってしまった。

D

「a_iの数『以外』にする」というのはどういうふうにやるんだろう?

E

とりあえず平衡二分探索木でやるのが思い浮かんだ。
平衡二分探索木を書くのは初めてで、他のやり方もありそうだけれども、
丁度ライブラリを作っておいていたのでこの機会に慣れておくかと思い書き始めた。
要素の追加・削除のない場合はもっと簡単なデータ構造で良いのかな。
まあでもライブラリ貼り付けるだけなら変わらんし、計算量も定数倍?だからどっちでもいいだろ(あんまりわかってない)。
http://www.slideshare.net/iwiwi/2-12188757を参考にxorの遅延評価を実装する。
しかしそのスライドでいうpushをどういうふうに入れたらいいかわからない!

SystemTest

ABC通った

結果

A: +488 (00:06)
B: +948 (00:13)
C: +1188 (00:52)
Rank: 182/1515 (Div.2 only)
Rating: 16461697

Practice

E、コンテスト終了数秒後!にテストケースを通るものができた…
…が、それはPracticeでSubmitしてみたらTLEした。
あれ?うーん?
クエリがO(n)になってる。遅延評価になってない!
うーん
なんとなくわかったけど、まだWAする…
あー、xorはsumに対して遅延できなくない?理解した。一様な加算なら、sumに対して遅延できる、なるほどね。
まあでも理解できてよかった。
色々試して、ビットごとにカウント持たせたら平衡二分探索木でできそうだ。が、微妙にTLEする…
updateを減らしたら通った!

コメント

色々慣れよう。

コード

PracticeでACしたEのコード。
ただし、この問題に使っていないような平衡二分探索木の処理は間違っている可能性あり

#include <string>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#include <cassert>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#if defined(_MSC_VER)
#define aut(r,v) auto r = (v)
#else
#define aut(r,v) typeof(v) r = (v)
#endif
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define all(o) (o).begin(), (o).end()
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define mset(m,v) memset(m,v,sizeof(m))
using namespace std;
typedef long long ll; typedef vector<int> vi; typedef vector<ll> vl; typedef pair<ll,ll> pll; typedef vector<pll> vpll; typedef vector<string> vs;
const int INF = 0x3f3f3f3f; const ll INFL = 0x3f3f3f3f3f3f3f3fLL;

typedef int Val;
#define BITS 20
struct Node {
    Val val; int priority;
    Node *ch[2];
    //ここに欲しい情報(値のsum, 値のmin, etc.)
    //splitのためにデフォルトでsizeがある
    int size;
    int count[BITS]; int xorx;
    //欲しい情報の初期値を設定する
    Node(Val v, int p)
        : val(v), priority(p)
        , size(1), xorx(0) { ch[0] = ch[1] = NULL; mset(count, 0); }
};
//NULL用に関数を作っておくと便利(Nodeのコンストラクタと同じく初期値に注意)
int val(Node *x) { assert(x); return x->val; }
int size(Node *x) { return !x ? 0 : x->size; }
int count(Node *x, int j) {
    return !x ? 0 : ((x->xorx>>j)&1 ? size(x) - x->count[j] : x->count[j]);
}

Node *update(Node *x) {
    //ここで欲しい情報の更新を行う
    if(!x) return x;
    x->size = size(x->ch[0]) + 1 + size(x->ch[1]);
    rep(j, BITS) {
        x->count[j] = count(x->ch[0], j) + ((val(x)>>j)&1) + count(x->ch[1], j);
        if((x->xorx>>j)&1)
            x->count[j] = x->size - x->count[j];
    }
    if(x->ch[0]) x->ch[0]->xorx ^= x->xorx;
    if(x->ch[1]) x->ch[1]->xorx ^= x->xorx;
    x->val ^= x->xorx; x->xorx = 0;
    return x;
}
Node *link(Node *x, Node *c, bool b) {
    x->ch[b] = c; return update(x);
}
Node *merge(Node *x, Node *y) {
    x = update(x); y = update(y);
    if(!x || !y) return x ? x : y;
    if(x->priority < y->priority) {
        return link(x, merge(x->ch[1], y), 1);
    }else {
        return link(y, merge(x, y->ch[0]), 0);
    }
}
//サイズによってsplitする。 ([0,k) , [k,n))
pair<Node*, Node*> split(Node *t, int k) {
    if(!update(t)) return mp((Node*)NULL, (Node*)NULL);
    if(size(t->ch[0]) < k) {
        aut(u, split(t->ch[1], k - size(t->ch[0]) - 1));
        return mp(link(t, u.first, 1), u.second);
    }else {
        aut(u, split(t->ch[0], k));
        return mp(u.first, link(t, u.second, 0));
    }
}
Node *singleton(Val val) { return update(new Node(val, rand())); }

int rnd(int x) {
    return (rand()*(RAND_MAX+1)+rand())%x;
}
//#define RANDOM_INPUT
int main() {
    Node *t = NULL;
    int n, m;
    scanf("%d", &n);
//  srand(clock());
    rep(i, n) {
        int a;
#ifndef RANDOM_INPUT
        scanf("%d", &a);
#else
        a = rnd(1000000);
#endif
        t = merge(t, singleton(a));
    }
    scanf("%d", &m);
    clock_t cl = clock();
    rep(i, m) {
        int y, l, r;
#ifndef RANDOM_INPUT
        scanf("%d%d%d", &y, &l, &r);
#else
        y = rnd(2)+1; l = rnd(n)+1; r = rnd(n)+1; if(l > r) swap(l, r);
#endif
        l--; r--; r ++;
        Node *tl, *tm, *tr;
        pair<Node*,Node*> p, q;
        p = split(t, l);
        q = split(p.second, r-l);
        tl = p.first; tm = q.first; tr = q.second;
        if(y == 1) {
            ll s = 0;
            rep(j, BITS)
                s += (ll)count(tm, j) << j;
#ifndef RANDOM_INPUT
            cout << s << endl;
#endif
        }else if(y == 2) {
            int x;
#ifndef RANDOM_INPUT
            scanf("%d", &x);
#else
            x = rnd(1000000);
#endif
            tm->xorx ^= x;
        }
        t = merge(merge(tl, tm), tr);
        if(0){
            cerr << "t: ";
            int i = 0;
            while(1) {
                int x = 0;
                pair<Node*,Node*> p = split(t, i);
                if(p.second == NULL) goto break_;
                pair<Node*,Node*> q = split(p.second, 1);
                x = q.first->val;
                t = merge(merge(p.first, q.first), q.second);
                cerr << x << " ";
                i ++;
            }
            break_:;
            cerr << endl;
        }
    }
    cerr << "time: " << (clock() - cl) << endl;
    return 0;
}