WUPC2nd G - だるま落とし

問題

日本語なので本文参照(http://wupc2nd.contest.atcoder.jp/tasks/wupc_07


次のようなクエリm個に答える。
高さhのだるまを、一番上に重ねる。
高さyの場所をハンマーで叩く。


このとき、ハンマーがあたらないならmiss,
複数のだるまに当たるならstop,
ひとつだけのだるまに当たるなら、そのだるまを取り除き、goを出力する。

制約条件

n, m≦100000
h≦100000
y≦10^12

方針

適当に平方分割したら通った。
クエリを√n回やるごとに、バケットを再構築する。


バケットごとに合計の高さをもっておくと、探索がO(√n)でできて、
だるまの追加はO(1), 削除はO(√n)でできる。


当たるだるまを見つけるには、だるまの上端がハンマーの下端を超えるまで、
次のだるまを見ていけばよい。


想定解はbinary indexed tree + 二分探索らしい。

ソースコード

const int SZ = 400;
int n, q, x;
int a[200000];
vector<pair<ll, vi> > block;
 
void init(){
	n = 0;
	rep(i, block.size()) rep(j, block[i].second.size()) 
	a[n++] = block[i].second[j];
}
void rebuild(){
	block.clear();
	vi v;
	ll s = 0;
	rep(i, n){
		s += a[i];
		v.pb(a[i]);
		if(v.size() == SZ){
			block.pb(mp(s, v));
			s = 0;
			v.clear();
		}
	}
	if(v.size()) block.pb(mp(s, v));
}
 
int main(){
	cin >> n >> q >> x;
	
	rep(i, n) cin >> a[i];
	rebuild();
	
	rep(it, q){
		string op;
		ll y;
		cin >> op >> y;
		if(op[0] == 'a'){
			if(block.back().second.size() >= SZ){
				block.pb(mp(0, vi(0)));
			}
			block.back().second.pb(y);
			block.back().first += y;
		}
		else{
			ll h = 0;
			int i, j;
			for(i = 0; i < (int)block.size(); i++){
				if(h + block[i].first > y - x) break;
				h += block[i].first;
			}
			if(i == (int)block.size()){
				cout << "miss" << endl;
				continue;
			}
			
			for(j = 0; j < (int)block[i].second.size(); j++){
				if(h + block[i].second[j] > y - x) break;
				h += block[i].second[j];
			}
			if(i == (int)block.size() - 1 && j >= (int)block[i].second.size() - 1){
			}
			else if(!(h <= y - x && y + x <= h + block[i].second[j])){
				cout << "stop" << endl;
				continue;
			}
			
			cout << "go" << endl;
			ll tmp = block[i].second[j];
			block[i].second.erase(block[i].second.begin() + j);
			block[i].first -= tmp;
			
			if(it % SZ == SZ - 1) init(), rebuild();
		}
	}
	return 0;
}