【Codeforces】CF 2021 C2

Adjust The Presentation (Hard Version)

#数据结构 #模拟

题目描述

This is the hard version of the problem. In the two versions, the constraints on q q q and the time limit are different. In this version, 0 ≤ q ≤ 2 ⋅ 1 0 5 0 \leq q \leq 2 \cdot 10^5 0q2105. You can make hacks only if all the versions of the problem are solved.

A team consisting of n n n members, numbered from 1 1 1 to n n n, is set to present a slide show at a large meeting. The slide show contains m m m slides.

There is an array a a a of length n n n. Initially, the members are standing in a line in the order of a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,,an from front to back. The slide show will be presented in order from slide 1 1 1 to slide m m m. Each section will be presented by the member at the front of the line. After each slide is presented, you can move the member at the front of the line to any position in the lineup (without changing the order of the rest of the members). For example, suppose the line of members is [ 3 , 1 , 2 , 4 ] [\color{red}{3},1,2,4] [3,1,2,4]. After member 3 3 3 presents the current slide, you can change the line of members into either [ 3 , 1 , 2 , 4 ] [\color{red}{3},1,2,4] [3,1,2,4], [ 1 , 3 , 2 , 4 ] [1,\color{red}{3},2,4] [1,3,2,4], [ 1 , 2 , 3 , 4 ] [1,2,\color{red}{3},4] [1,2,3,4] or [ 1 , 2 , 4 , 3 ] [1,2,4,\color{red}{3}] [1,2,4,3].

There is also an array b b b of length m m m. The slide show is considered good if it is possible to make member b i b_i bi present slide i i i for all i i i from 1 1 1 to m m m under these constraints.

However, your annoying boss wants to make q q q updates to the array b b b. In the i i i-th update, he will choose a slide s i s_i si and a member t i t_i ti and set b s i : = t i b_{s_i} := t_i bsi:=ti. Note that these updates are persistent, that is changes made to the array b b b will apply when processing future updates.

For each of the q + 1 q+1 q+1 states of array b b b, the initial state and after each of the q q q updates, determine if the slideshow is good.

输入格式

Each test contains multiple test cases. The first line contains the number of test cases t t t ( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1t104). The description of the test cases follows.

The first line of each test case contains three integers n n n, m m m and q q q ( 1 ≤ n , m ≤ 2 ⋅ 1 0 5 1 \le n, m \le 2 \cdot 10^5 1n,m2105; 0 ≤ q ≤ 2 ⋅ 1 0 5 0 \leq q \leq 2 \cdot 10^5 0q2105) — the number of members and the number of sections.

The second line of each test case contains n n n integers a 1 , a 2 , … , a n a_1,a_2,\ldots,a_n a1,a2,,an ( 1 ≤ a i ≤ n 1 \le a_i \le n 1ain) — the initial order of the members from front to back. It is guaranteed that each integer from 1 1 1 to n n n appears exactly once in a a a.

The third line of each test case contains m m m integers b 1 , b 2 , … , b m b_1, b_2, \ldots, b_m b1,b2,,bm ( 1 ≤ b i ≤ n 1 \le b_i \le n 1bin) — the members who should present each section.

Each of the next q q q lines contains two integers s i s_i si and t i t_i ti ( 1 ≤ s i ≤ m 1 \le s_i \le m 1sim, 1 ≤ t i ≤ n 1 \le t_i \le n 1tin) — parameters of an update.

It is guaranteed that the sum of n n n, the sum of m m m and the sum of q q q over all test cases do not exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2105 respectively.

输出格式

For each test case, output q + 1 q+1 q+1 lines corresponding to the q + 1 q+1 q+1 states of the array b b b. Output “YA” if the slide show is good, and “TIDAK” otherwise.

You can output the answer in any case (upper or lower). For example, the strings “yA”, “Ya”, “ya”, and “YA” will be recognized as positive responses.

样例 #1

样例输入 #1

3
4 2 2
1 2 3 4
1 1
1 2
1 1
3 6 2
1 2 3
1 1 2 3 3 2
3 3
2 2
4 6 2
3 1 4 2
3 1 1 2 3 4
3 4
4 2

样例输出 #1

YA
TIDAK
YA
YA
TIDAK
YA
TIDAK
YA
YA

解法

解题思路

e a s y easy easy版本中,我们知道, b b b中每个数第一次出现时,必须保证这个数在 a a a中的下标(假设为 i i i),那么 a [ i − 1 ] a[i-1] a[i1]这个数字在 b b b中出现过。

即,如下的数列是不合法,因为 4 4 4对应的 a a a中位置的前一个数是 3 3 3,而 3 3 3不在 b b b 4 4 4之前出现过。
a [ 1 , 2 , 3 , 4 , 5 ]      b [ 1 , 2 , 4 , 3 , 5 ] a[1,2,3,4,5] \ \ \ \ b[1,2,4,3,5] a[1,2,3,4,5]    b[1,2,4,3,5]

那么,我们知道,每个数都只与第一次出现有关,它对它前面一个第一次出现的数,和后面第一个出现的数有影响。

因此我们维护一个 p o s pos pos数组,表示每个数第一次出现的位置。

考虑修改操作对答案的影响,修改操作我们看做删除后再插入。

那么删除的影响是什么?

1. 1. 1. 如果删除的那个数不是第一次出现的数,那么显然没有影响。
2. 2. 2. 如果删除的那个数是第一次出现的数,那么它对它前驱和后继的影响就该删去,然后它的后继对它的前驱的影响就要增加。

插入的影响又是什么? 其实就是反过来再来一遍:

1. 1. 1. 如果插入的那个数不是第一次出现的数,那么显然没有影响。
2. 2. 2. 如果插入的那个数是第一次出现的数,那么它对它前驱和后继的影响就该增加,然后它的后继对它的前驱的影响就该删除。

对于如何判断某个数是否是第一个出现的数,我们可以对每种数 ( a [ i ] ≤ n ) (a[i]\leq n) (a[i]n)开一个 s t d : : s e t std::set std::set,用于动态维护存在的下标即可。

代码


void solve() {
	int n, m, q;
	std::cin >> n >> m >> q;


	std::vector<int>a(n + 1), b(m + 1), pos(n + 1);
	for (int i = 1; i <= n; ++i) {
		std::cin >> a[i];
		pos[a[i]] = i;
	}

	for (int i = 1; i <= m; ++i) {
		std::cin >> b[i];
	}

	std::set<int>fst;
	fst.insert(0);

	std::vector<std::set<int>>st(n + 1);

	int cnt = 0;
	auto add = [&](int num, int idx, int f) {
		auto nxt = fst.upper_bound(idx);
		if (nxt != fst.end()) {
			if (pos[num] + 1 != pos[b[*nxt]]) {
				cnt += f;  // 增加 nxt 对 self 的影响
			}
		}

		auto pre = prev(fst.lower_bound(idx));
		if (pos[b[*pre]] + 1 != pos[num]) {
			cnt += f;
		}

		if (nxt != fst.end()) {
			if (pos[b[*pre]] + 1 != pos[b[*nxt]]) {
				cnt -= f;
			}
		}

		};

	for (int i = 1; i <= m; i++) {
		if (st[b[i]].empty()) {
			add(b[i], i, 1);
			fst.insert(i);
		}
		st[b[i]].insert(i);
	}

	std::cout << (cnt ? "TIDAK" : "YA") << "\n";

	while (q--) {
		int s, t;
		std::cin >> s >> t;

		if (*st[b[s]].begin() == s) {
			fst.erase(s);
			add(b[s], s, -1);
			st[b[s]].erase(s);
			if (!st[b[s]].empty()) {
				add(b[s], *st[b[s]].begin(), 1);
				fst.insert(*st[b[s]].begin());
			}
		}
		else {
			st[b[s]].erase(s);
		}

		b[s] = t;

		if (!st[t].empty() && *st[t].begin() > s) {
			fst.erase(*st[t].begin());
			add(t, *st[t].begin(), -1);
		}
		st[t].insert(s);
		if (*st[t].begin() == s) {
			add(t, *st[t].begin(), 1);
			fst.insert(s);
		}
		std::cout << (cnt ? "TIDAK" : "YA") << "\n";

	}

}

signed main() {
	std::ios::sync_with_stdio(0);
	std::cin.tie(0);
	std::cout.tie(0);

	int t = 1;
	std::cin >> t;

	while (t--) {
		solve();
	}
};```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值