Codeforces 400(#234 Div2 only) E Inna and Binary Logic

問題

Innaは整数の配列a[i]を使って次のようなことをする。


a[i]を一列に全部書く。これをa1[i]とする。
次に、n - 1個の(a1[i] and a1[i + 1])を書く。(ただしandはビット演算のand)
これをa2[i]とする。
次にn - 2個の(a2[i] and a2[i + 1])を書く……
を数字が最後の一つになるまで繰り替えす。


Innaが書いた全ての数の和をsumとする。


このとき次のクエリm個に答えよ。
a[i]のu[i]番目の数をv[i]に変更する。
この数列でInnaが数字を最初から書いたときのsumを出力せよ。
クエリで変更されたa[i]は、次のクエリにもそのまま残るものとする。

制約条件

n, m≦10^5
0≦a[i]≦10^5

方針

ビット演算のandなのでビットごとに独立に考えていい。
クエリを全部読んでおいて、ビットごとにクエリを処理して、
i番目のビットのせいでInnaが書いた数字の和を答えに足していけばよい。


今、ビット毎に独立に考えて操作をするので、a[i]は0, 1だけからなっている。
1がn個並んでいると、Innaはn + (n - 1) + (n - 2) + = n * (n + 1) / 2個の1を書くことになる。
なので、数字を変更すると、連続する1の個数が変化するので、
その分だけ上の式にしたがってsumを変更してやればよい。


連続する1は、binary indexed treeに0の場所を覚えさせておけば、
O(log n)で検索できるが、binary indexed treeを二分探索するO((log n) ^ 2)とかいう頭の悪いことをやってもギリギリ通った。

ソースコード

const int MX = 100010;
int n, m, a[MX], cur[MX];
int u[MX], v[MX];
ll ans[MX];

int bit[MX];
int sum(int i){
	int res = 0;
	for(++i ; i; i -= i & -i) res += bit[i];
	return res;
}
void add(int i, int x){
	for(++i ; i < MX; i += i & -i) bit[i] += x;
}

void change_bit(ll &ans, int pos, int on, int bit_pos){
	
	int left, right;
	int lo = pos, hi = n, mid;
	
	while(lo + 1 < hi){
		mid = (lo + hi) / 2;
		
		if(sum(mid) - sum(pos) != mid - pos) hi = mid;
		else lo = mid;
	}
	right = lo - pos;
	
	lo = -1; hi = pos;
	
	while(lo + 1 < hi){
		mid = (lo + hi) / 2;
		
		if(sum(pos - 1) - sum(mid - 1) != pos - mid) lo = mid;
		else hi = mid;
	}
	left = pos - hi;
	
	if(on){
		ans -= (1ll << bit_pos) * (left + 1) * left / 2;
		ans -= (1ll << bit_pos) * (right + 1) * right / 2;
		ans += (1ll << bit_pos) * (left + right + 2) * (left + right + 1) / 2;
		
		add(pos, 1);
	}
	else{
		ans += (1ll << bit_pos) * (left + 1) * left / 2;
		ans += (1ll << bit_pos) * (right + 1) * right / 2;
		ans -= (1ll << bit_pos) * (left + right + 2) * (left + right + 1) / 2;
		
		add(pos, -1);
	}
}


int main(){
	cin >> n >> m;
	rep(i, n) cin >> a[i];
	rep(i, m){
		cin >> u[i] >> v[i];
		u[i]--;
	}
	
	rep(pos, 32){
		memset(bit, 0, sizeof(bit));
		ll bit_ans = 0;
		
		rep(i, n) if(a[i] >> pos & 1) change_bit(bit_ans, i, 1, pos);
		rep(i, m){
			int prev = sum(u[i]) - sum(u[i] - 1);
			int next = v[i] >> pos & 1;
			
			if(prev != next) change_bit(bit_ans, u[i], next, pos);
			ans[i] += bit_ans;
		}
	}
	
	rep(i, m) cout << ans[i] << endl;
	
	return 0;
}