Codeforces 173 E. Camping Groups
問題
n人の人がいて、それぞれの責任感r[i]および年齢a[i]が与えられる。
この人の中から、次の条件を満たすグループを作りたい。
- 責任感r[i]が最大の人(タイの場合はタイの中の誰でもいい)をリーダーとする。
- リーダーと、他の全員の年齢の差がkである。
このとき、次のような質問q個に答えよ。
- 与えられた番号の人x, yが共に同じグループに入るときの、グループの人数の最大値を求める
制約条件
n, q≦10^5
k, r[i], a[i]≦10^9
方針
リーダーの年齢がちょうどaのときのグループの最大人数をf(a)とすると、
それぞれの質問について、
責任感が、max(r[x], r[y])以上で、年齢がmax(a[x], a[y]) - k以上min(a[x], a[y]) + k以下の人iについてf(a[i])の最大値を効率的に求められたらよい。
これは、クエリをrの大きい順に並べて、Range Minimum Queryに(a, f(a))をrの大きい順に代入していきつつ、
その時点での区間の最大値を取ることでlog n時間で求められる。
リーダーの年齢がちょうどaのときのグループの最大人数はどうやって求めるかというと、
今度は人(r, a)を、rの小さい順に並べて、BITのaに1を足して、a-k以上a-k以下の区間の点の個数を求めれば、log nで計算できる。
ただしaの値が大きいので座標圧縮が必要。
ソースコード
const int MX = 131072; int n, k, q, r[MX], a[MX], x[MX], y[MX]; int bit[MX], mx[MX], ans[MX], N, data[MX * 2]; pi ps[MX], qs[MX]; inline int sum(int i){ int res = 0; for(; i; i -= i & -i) res += bit[i]; return res; } inline void add(int i, int x){ for(; i < MX; i += i & -i) bit[i] += x; } int get(int a, int b, int l, int r, int k){ if(b <= l || a >= r) return 0; if(a <= l && r <= b) return data[k]; return max(get(a, b, l, (l+r) / 2, k*2 + 1), get(a, b, (l+r) / 2, r, k*2 + 2)); } void update(int x, int v){ x += N-1; data[x] = max(data[x], v); while(x > 0){ x = (x - 1) / 2; data[x] = max(data[x], max(data[x * 2 + 1], data[x * 2 + 2])); } } void run() { int sz = 0; map<int, int> m; map<int, int>::iterator it; cin >> n >> k; rep(i, n) cin >> r[i]; rep(i, n) cin >> a[i], ps[i] = mp(r[i], a[i]), m[a[i]] = 0; sort(ps, ps + n); fr(i, m) i->second = sz++; m[inf] = sz++; for(N = 1; N < sz; N *= 2); rep(i, n){ int j = i; while(j < n-1 && ps[j+1].first == ps[i].first) j++; for(int p = i; p <= j; p++) add(m[ps[p].second] + 1, 1); for(int p = i; p <= j; p++){ it = m.upper_bound(min((ll)ps[p].second + k, inf - 1ll)); int u = it->second; it = m.lower_bound(max((ll)ps[p].second - k, 0ll)); int l = it->second, c = m[ps[p].second]; mx[p] = max(0, sum(u) - sum(l)); } i = j; } cin >> q; rep(i, q){ cin >> x[i] >> y[i]; x[i]--; y[i]--; qs[i] = mp(max(r[x[i]], r[y[i]]), i); } sort(qs, qs + q); for(int i = q-1, j = n; i >= 0; i--){ while(j > 0 && qs[i].first <= ps[j-1].first){ j--; update(m[ps[j].second], mx[j]); } int s = x[qs[i].second], t = y[qs[i].second]; if(a[s] > a[t]) swap(s, t); it = m.upper_bound(min((ll)a[s] + k, inf - 1ll)); int u = it->second; it = m.lower_bound(max((ll)a[t] - k, 0ll)); int l = it->second; ans[qs[i].second] = l < u ? get(l, u, 0, N, 0) : 0; if(ans[qs[i].second] == 0) ans[qs[i].second] = -1; } rep(i, q) cout << ans[i] << endl; }