Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Problem L: RMQ 2

Problem

長さ$N$の2つの数列$A$と$B$が与えられる。はじめ、数列$A$の$i$項目は$a_i$であり、数列$B$の$i$項目は$b_i$である。

以下のような形式の命令文が合計$Q$個与えられるので、与えられた順に処理を行うプログラムを作成せよ。

各命令文は3つの整数$x,y,z$で表される。

数列$A$の$y$項目の値を$z$にする。 ($x=1$のとき)

数列$B$の$y$項目の値を$z$にする。 ($x=2$のとき)

数列$A$の$y$項目から$z$項目の中で最小の値を見つけて報告する。 ($x=3$のとき)

数列$B$の$y$項目から$z$項目の中で最小の値を見つけて報告する。 ($x=4$のとき)

数列$A$を、数列$B$と全く同じになるように変更する。 ($x=5$のとき)

数列$B$を、数列$A$と全く同じになるように変更する。 ($x=6$のとき)

Input

入力は以下の形式で与えられる。

$N$

$a_{1}$ $a_{2}$ ... $a_{N}$

$b_{1}$ $b_{2}$ ... $b_{N}$

$Q$

$x_1$ $y_1$ $z_1$

$x_2$ $y_2$ $z_2$

...

$x_Q$ $y_Q$ $z_Q$

Constraints

入力は以下の条件を満たす。

$2 \le N \le 2 \times 10^5$

$2 \le Q \le 2 \times 10^5$

$1 \le a_i \le 10^9$

$1 \le b_i \le 10^9$

$1 \le x_i \le 6$

$1 \le y_i \le N $ ($1 \le x_i \le 4$のとき)

$y_i = -1$ ($x_i=5, 6$のとき)

$1 \le z_i \le 10^9$ ($x_i=1, 2$のとき)

$y_i \le z_i \le N$ ($x_i=3, 4$のとき)

$z_i = -1$ ($x_i=5, 6$のとき)

入力はすべて整数

Output

$x=3$または$x=4$の命令文が入力で与えられる度に、見つけた値を1行に出力する。

Sample Input 1

5
1 3 5 7 9
6 2 3 2 6
10
1 3 4
3 4 5
4 2 3
5 -1 -1
2 3 8
3 2 5
4 3 3
1 1 1
6 -1 -1
3 1 5

Sample Output 1

7
2
2
8
1

Solution in C (judge verdict: Accepted)

// AOJ 3024 RMQ 2
// 2019.4.2 bal4u

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INF 0x7fffffff

#if 1
#define gc() getchar_unlocked()
#define pc(c) putchar_unlocked(c)
#else
#define gc() getchar()
#define pc(c) putchar(c)
#endif
int in()
{
	int n = 0, c = gc();
	do n = 10 * n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

void out(int n)
{
	int i;
	char ob[30];

	if (!n) pc('0');
	else {
		i = 0; while (n) ob[i++] = n % 10 + '0', n /= 10;
		while (i--) pc(ob[i]);
	}
	pc('\n');
}


//// セグメント木
int seg[2][1 << 19]; int sz;

void segInit(int n) {
	sz = 1; while (sz < n) sz <<= 1;
	memset(seg, INF, sizeof(seg));
}

// k番目（0-index）の値を v に変更
void update(int id, int k, int v)
{
	int a, b;

	k += sz - 1;
//	if (seg[id][k] == v) return;
	seg[id][k] = v;
	while (k > 0) {
		k = (k - 1) >> 1;
		a = seg[id][(k << 1) + 1];
		b = seg[id][(k << 1) + 2];
		seg[id][k] = (a <= b)? a: b;
	}
}

// 空間 [a, b) 内の最小値
int getMin(int id, int a, int b, int k, int l, int r)
{
	int left, right;

	if (r <= a || b <= l) return INF;
	if (a <= l && r <= b) return seg[id][k];
	left = getMin(id, a, b, (k << 1) + 1, l, (l + r) >> 1);
	right = getMin(id, a, b, (k << 1) + 2, (l + r) >> 1, r);
	return left <= right ? left : right;
}


//// 本問題
typedef struct { int y, p, n; } T;  // 位置と更新前後の値
T memo[2][200005]; int len[2];

int main()
{
	int i, k, N, Q, x, y, z;
	int syn;

	N = in();
	segInit(N);            // セグメント木の初期化
	for (i = 0; i < N; i++) update(0, i, in());
	for (i = 0; i < N; i++) update(1, i, in());

	Q = in(), syn = 0;
	while (Q--) {
		x = in(), y = in()-1, z = in();      // 0-index
		if (x == 1 || x == 2) {
			x--;   // 0と1にする. 0->A, 1->B
			if (syn) {
				// 位置と更新前後の値を記録
				k = len[x]++;
				memo[x][k].y = y, memo[x][k].n = z;
				memo[x][k].p = seg[x][y+(sz-1)];     // 元の値は y+(sz-1) の位置にある
			}
			update(x, y, z);
		}
		else if (x == 3 || x == 4) out(getMin(x-3, y, z, 0, 0, sz));
		else {
			x -= 5;   // 0と1にする. 0->A, 1->B
			if (syn) {
				// 元に戻して、相手のしてきた変更を施し、相手と同じにする
				for (i = len[x] - 1; i >= 0; i--)   // 戻す作業
					update(x, memo[x][i].y, memo[x][i].p);
				for (i = 0; i < len[!x]; i++)       // 相手に同期
					update(x, memo[!x][i].y, memo[!x][i].n);
				len[0] = len[1] = 0;
			}
			else {
				memcpy(seg[x], seg[!x], sizeof(int)*sz*2);
				syn = 1;
			}
		}
	}
	return 0;
}