Atcoder Regular Contest 010 D - 情報伝播

問題

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


座標平面上に味方n人と敵m人がいる。
それぞれの座標が与えられる。


味方は、自分から最も近い敵よりも、厳密に近くにいる味方全員に情報を伝えられる。
味方全員に情報を伝えたいとき、最初に情報を伝えるべき味方の数の最小値はいくつか。

制約条件

n≦4000
m≦100000
座標の絶対値は10^9以下
m>1000のとき、敵は10^9以下の範囲にランダムに散らばっている

方針

それぞれの味方ごとに、最も近い敵が短い時間で求められれば、
有向グラフを作ることができるので、あとは強連結成分分解して入次数0の頂点を数えればそれが答えになる。


最も近い敵はバケット法で求めた。
敵が一様分布していることが保証されているので、
平面を適当にバケットに区切ってやれば、どのバケットに入る敵の期待値も同じになる。
なので、適当に自分の周囲のバケットだけを見れば、最も近い敵が短い時間でわかる。

ソースコード

int n, m;
int x[5000], y[5000];
int sx[100000], sy[100000];
vector<vi> g;

vi s[30][30];

inline ll dist(ll x, ll y){
	return x * x + y * y;
}

int main(){
	vi xs, ys;
	
	cin >> n;
	rep(i, n) cin >> x[i] >> y[i];
	cin >> m;
	rep(i, m){
		cin >> sx[i] >> sy[i];
		xs.pb(sx[i]);
		ys.pb(sy[i]);
	}
	sort(all(xs));
	xs.erase(unique(all(xs)), xs.end());
	sort(all(ys));
	ys.erase(unique(all(ys)), ys.end());
	
	g.resize(n);
	
	rep(i, m){
		int x = lower_bound(all(xs), sx[i]) - xs.begin();
		int y = lower_bound(all(ys), sy[i]) - ys.begin();
		
		s[x / 4000][y / 4000].pb(i);
	}
	
	rep(i, n){
		int xi = lower_bound(all(xs), x[i]) - xs.begin();
		int yi = lower_bound(all(ys), y[i]) - ys.begin();
		ll d = (1ull << 63) - 1;
		
		xi /= 4000;
		yi /= 4000;
		for(int j = xi - 1; j < xi + 2; j++) for(int k = yi - 1; k < yi + 2; k++){
			if(j < 0 || j >= xs.size()) continue;
			if(k < 0 || k >= ys.size()) continue;
			
			rep(l, s[j][k].size()){
				int xx = sx[s[j][k][l]], yy = sy[s[j][k][l]];
				d = min(d, dist(xx - x[i], yy - y[i]));
			}
		}
		rep(j, n) if(dist(x[i] - x[j], y[i] - y[j]) < d) g[i].pb(j);
	}
	
	vector<vi> scc;
	stronglyConnectedComponents(g, scc);
	vi to(n);
	vi in(scc.size());
	vector<vi> e(scc.size());
	
	rep(i, scc.size()) rep(j, scc[i].size()) to[scc[i][j]] = i;
	rep(i, n) rep(j, g[i].size()){
		int a = to[i], b = to[g[i][j]];
		if(a != b){
			e[a].pb(b);
			in[b]++;
		}
	}
	
	int ans = 0;
	rep(i, scc.size()) if(in[i] == 0) ans++;
	cout << ans << endl;
	
	return 0;
}