結果
| 問題 |
No.3122 Median of Medians of Division
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-04-20 06:31:32 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
TLE
|
| 実行時間 | - |
| コード長 | 6,779 bytes |
| コンパイル時間 | 3,420 ms |
| コンパイル使用メモリ | 254,392 KB |
| 実行使用メモリ | 146,200 KB |
| 最終ジャッジ日時 | 2025-04-20 06:31:45 |
| 合計ジャッジ時間 | 11,559 ms |
|
ジャッジサーバーID (参考情報) |
judge5 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | -- * 1 |
| other | TLE * 1 -- * 39 |
ソースコード
// # pragma GCC target("avx2")
# pragma GCC optimize("O3")
# pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
// 二次元 Fenwick Tree:
// - x ∈ [0..n-1], y は各 x で事前に登録された値集合から選択
struct BIT2D {
int n;
vector<vector<int>> ys, t;
BIT2D(int _n = 0) : n(_n), ys(n+1) {}
// 構築フェーズ:(x,y) が将来更新で使われうることを登録
void fake_add(int x, int y) {
for(int i = x+1; i <= n; i += i & -i)
ys[i].push_back(y);
}
// fake_add 後に一度だけ呼び出し、内部の BIT 配列を初期化
void init() {
t.resize(n+1);
for(int i = 1; i <= n; i++) {
auto &v = ys[i];
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
t[i].assign(v.size()+1, 0);
}
}
// BIT における (x,y) への加算
void update(int x, int y, int v) {
for(int i = x+1; i <= n; i += i & -i) {
int k = int(lower_bound(ys[i].begin(), ys[i].end(), y) - ys[i].begin()) + 1;
for(int j = k; j < (int)t[i].size(); j += j & -j)
t[i][j] += v;
}
}
// [0..x]×[0..y] の累積和
int query_prefix(int x, int y) const {
int res = 0;
for(int i = x+1; i > 0; i -= i & -i) {
int k = int(upper_bound(ys[i].begin(), ys[i].end(), y) - ys[i].begin());
for(int j = k; j > 0; j -= j & -j)
res += t[i][j];
}
return res;
}
// [xl..xr]×[yl..yr] の和
int query(int xl, int xr, int yl, int yr) const {
if(xl > xr || yl > yr) return 0;
return query_prefix(xr, yr)
- query_prefix(xl-1, yr)
- query_prefix(xr, yl-1)
+ query_prefix(xl-1, yl-1);
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, Q;
cin >> N >> Q;
vector<ll> A(N);
for(int i = 0; i < N; i++) cin >> A[i];
struct Query { int type; int i, l, r; ll x; };
vector<Query> qs(Q);
// 1) 先読み:各位置 i の A 候補値を集める
vector<vector<ll>> posA_val(N);
for(int i = 0; i < N; i++)
posA_val[i].push_back(A[i]);
for(int qi = 0; qi < Q; qi++){
cin >> qs[qi].type;
if(qs[qi].type == 1){
cin >> qs[qi].i >> qs[qi].x;
--qs[qi].i;
posA_val[qs[qi].i].push_back(qs[qi].x);
} else {
cin >> qs[qi].l >> qs[qi].r;
--qs[qi].l; --qs[qi].r;
}
}
// 2) 座標圧縮
vector<ll> allA;
allA.reserve(N + Q);
for(int i = 0; i < N; i++){
auto &v = posA_val[i];
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for(ll x : v) allA.push_back(x);
}
sort(allA.begin(), allA.end());
allA.erase(unique(allA.begin(), allA.end()), allA.end());
int MA = allA.size();
// posA_val -> posA_comp (圧縮後の値)
vector<vector<int>> posA(N);
for(int i = 0; i < N; i++){
for(ll x : posA_val[i]){
int c = int(lower_bound(allA.begin(), allA.end(), x) - allA.begin());
posA[i].push_back(c);
}
sort(posA[i].begin(), posA[i].end());
posA[i].erase(unique(posA[i].begin(), posA[i].end()), posA[i].end());
}
// 隣接ペア Bc の取りうる値を先読み(posB)
vector<vector<int>> posB(max(0, N-1));
if(N >= 2){
for(int i = 0; i < N-1; i++){
auto &a = posA[i], &b = posA[i+1];
int min_a = a[0], min_b = b[0];
vector<int> tmp;
// max(a_j, b_k) = a_j となる a_j は a_j >= min_b
auto ita = lower_bound(a.begin(), a.end(), min_b);
tmp.insert(tmp.end(), ita, a.end());
// max(a_j, b_k) = b_k となる b_k は b_k > min_a
auto itb = upper_bound(b.begin(), b.end(), min_a);
tmp.insert(tmp.end(), itb, b.end());
sort(tmp.begin(), tmp.end());
tmp.erase(unique(tmp.begin(), tmp.end()), tmp.end());
posB[i] = move(tmp);
}
}
// 3) BIT2D を構築
BIT2D bitA(N);
for(int i = 0; i < N; i++)
for(int y : posA[i])
bitA.fake_add(i, y);
bitA.init();
BIT2D bitB(N >= 2 ? N-1 : 0);
if(N >= 2){
for(int i = 0; i < N-1; i++)
for(int y : posB[i])
bitB.fake_add(i, y);
bitB.init();
}
// 4) 初期状態を BIT に登録
vector<int> Ac(N);
for(int i = 0; i < N; i++){
Ac[i] = int(lower_bound(allA.begin(), allA.end(), A[i]) - allA.begin());
bitA.update(i, Ac[i], +1);
}
vector<int> Bc;
if(N >= 2){
Bc.resize(N-1);
for(int i = 0; i < N-1; i++){
Bc[i] = max(Ac[i], Ac[i+1]);
bitB.update(i, Bc[i], +1);
}
}
// 5) クエリ処理
for(auto &q : qs){
if(q.type == 1){
int idx = q.i;
int oldc = Ac[idx];
int newc = int(lower_bound(allA.begin(), allA.end(), q.x) - allA.begin());
// A 更新
bitA.update(idx, oldc, -1);
bitA.update(idx, newc, +1);
Ac[idx] = newc;
// 隣接ペア更新
if(N >= 2){
if(idx > 0){
int i2 = idx-1;
int boc = Bc[i2], bnc = max(Ac[i2], Ac[i2+1]);
if(boc != bnc){
bitB.update(i2, boc, -1);
bitB.update(i2, bnc, +1);
Bc[i2] = bnc;
}
}
if(idx+1 < N){
int i2 = idx;
int boc = Bc[i2], bnc = max(Ac[i2], Ac[i2+1]);
if(boc != bnc){
bitB.update(i2, boc, -1);
bitB.update(i2, bnc, +1);
Bc[i2] = bnc;
}
}
}
}
else {
int l = q.l, r = q.r;
int len = r - l + 1;
// 閾値 k の最大値を二分探索
int low = 0, high = MA;
while(high - low > 1){
int mid = (low + high) >> 1;
int ge = bitA.query(l, r, mid, MA-1);
int lt_pairs = (l < r && N >= 2)
? bitB.query(l, r-1, 0, mid-1)
: 0;
ll H = ll(ge)*2 + lt_pairs;
if(H > len) low = mid;
else high = mid;
}
// 圧縮前の値を出力
cout << allA[low] << "\n";
}
}
return 0;
}