Official

G - Range Sort Query Editorial by mechanicalpenciI


順列 \(P_i\) について \(P_i\leq x\) ならば \(A_i=0\)\(P_i\geq x+1\) ならば \(A_i=1\) とした \(01\)\(A\) を用意し、これがクエリによってどう変更されるか考えます。 もし、 \(x=K-1\) としたときと \(x=K\) としたときについて、すべてのクエリを処理した後の \(01\) 列が分かれば、その差分から \(P_i=k\) である \(i\) を求めることができます。具体的には前者では \(0\) , 後者では \(1\) であるような場所が \(1\) つだけ存在し、その場所が \(P_i=k\) であるようindex \(i\) の場所です。

クエリについて、まず \(C_i=1\), すなわち昇順にソートするものを考えます。\(A_{L_i}, A_{L_i+1}, \ldots ,A_{R_i}\)\(0\)\(a\) 個、 \(1\)\(b\)\((a+b=R_i-L_i+1)\) 含まれていたとします。このとき \(P_j\) \((L_i\leq j\leq R_i)\) の具体的な値が何であったかに関わらず、ソート後の順列に対応する \(01\) 列のこの範囲には \(a\) 個の \(0\)\(b\) 個の \(1\) が、この順で並びます。すなわち、 \(0,0,\ldots, (a個),\ldots,0,1,1,,\ldots, (b個),\ldots,1\) となります。これは次の操作と同値です。

  • \(S=A_{L_i}+A_{L_i+1}+\cdots +A_{R_i}\) を求める。
  • \(A_{L_i}, A_{L_i+1}, \ldots ,A_{R_i-S}\) の値を一括して \(0\) に変更する。
  • \(A_{R_i-S+1}, A_{R_i-S+2}, \ldots ,A_{R_i}\) の値を一括して \(1\) に変更する。

同様にして、\(C_i=2\), すなわち降順にソートする操作も \(01\) 列に対しては、

  • \(S=A_{L_i}+A_{L_i+1}+\cdots +A_{R_i}\) を求める。
  • \(A_{L_i}, A_{L_i+1}, \ldots ,A_{L_i+S-1}\) の値を一括して \(1\) に変更する。
  • \(A_{L_i+S}, A_{L_i+S+1}, \ldots ,A_{R_i}\) の値を一括して \(0\) に変更する。

という操作と同値である事が分かります。

これらの操作は遅延セグメント木によって行うことができます。 よって、初期状態の順列から \(01\) 列を構成し、遅延セグメント木の上でクエリによる更新操作を行い、最終的な \(01\) 列についてその差分を調べれば良いです。計算量は最初の構築および最後の差分検索に\(O(N)\), 更新はクエリごとに \(O(\log N)\) であるため全体で \(O(N+Q\log N)\) であり、十分高速です。よって、この問題を解く事が出来ました。

c++による実装例 :

#include <bits/stdc++.h>
#include <atcoder/lazysegtree>

using namespace std;
using namespace atcoder;

#define rep(i, n) for(int i = 0; i < n; ++i)

struct S { 	int sz, val; };

struct F { int k; };

S op(S l, S r) { return S{ l.sz + r.sz,l.val + r.val }; }

S e() { return S{ 0,0 }; }

S mapping(F f, S s) {
	if (f.k >= 0)return S{ s.sz,(f.k)*(s.sz) };
	else return s;
}

F composition(F l, F r) {
	if (l.k >= 0)return F{ l.k };
	else return F{ r.k };
}

F id() { return F{ -1 }; }


int main() {
	int n, q, k;
	int c, l, r;
	int x, y;
	
	cin >> n >> q >> k;
  
    vector<S> a(n), b(n);
  
	rep(i, n) {
		cin >> x;
		if (x < k)a[i] = { 1,0 };
		else a[i] = { 1,1 };
		if (x <= k)b[i] = { 1,0 };
		else b[i] = { 1,1 };
	}

	lazy_segtree<S, op, e, F, mapping, composition, id> sega(a);
	lazy_segtree<S, op, e, F, mapping, composition, id> segb(b);

	rep(i, q) {
		cin >> c >> l >> r;
		l--;
		x = sega.prod(l, r).val;
		y = segb.prod(l, r).val;
		if (c == 1) {
			sega.apply(l, r - x, F{ 0 });
			sega.apply(r - x, r, F{ 1 });
			segb.apply(l, r - y, F{ 0 });
			segb.apply(r - y, r, F{ 1 });
		}
		else {
			sega.apply(l, l + x, F{ 1 });
			sega.apply(l + x, r, F{ 0 });
			segb.apply(l, l + y, F{ 1 });
			segb.apply(l + y, r, F{ 0 });
		}
	}

	rep(i, n)if (sega.get(i).val != segb.get(i).val)cout << i + 1 << endl;

	return 0;
}

posted:
last update: