Luogu P6617 查找 Search

题目描述

https://www.luogu.com.cn/problem/P6617

简要题意:给定一个长度为 $n$ 的序列 $a_i$ 和一个整数 $k$,现在有 $m$ 次操作,操作有两种,第一种操作给定 $x,y$,将 $a_x$ 修改为 $y$;第二种操作给定一个区间 $[l,r]$,询问区间内是否存在两个数 $a_x+a_y=k$

$n,m,k\le 5\times 10^5$,强制在线

Solution

我们考虑对于每个数维护一个后继,$a_x$ 的后继定义为第一个大于 $x$ 的 $y$,且 $a_x+a_y=k$,且不存在 $z\in[x,y]$,$a_z=a_x$,这样我们查询就是求区间最小值是否小于等于 $r$

同时我们单点修改的话只会最多影响五个位置,我们令 $a_x$ 表示 $x$ 修改前的值,$a’_x$ 表示 $x$ 修改后的值,那么这五个位置是 $x$,第一个值为 $a_x$ 的下标小于 $x$ 的位置,第一个值为 $k-a_x$ 的下标小于 $x$ 的位置,第一个值为 $a’_x$ 的下标小于 $x$ 的位置,第一个值为 $k-a’_x$ 的下标小于 $x$ 的位置

我们用 $set$ 维护每种权值对应的下标,每次修改暴力查询这五个位置的后继即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#define INF 1000000000
#define maxn 500010
using namespace std;

int n, m, k, a[maxn];
set<int> S[maxn];

#define lc i << 1
#define rc i << 1 | 1
int T[maxn * 4];
inline void maintain(int i) { T[i] = min(T[lc], T[rc]); }
void update(int i, int l, int r, int k, int v) {
if (l == r) return T[i] = v, void();
int m = l + r >> 1;
if (k <= m) update(lc, l, m, k, v);
else update(rc, m + 1, r, k, v);
maintain(i);
}
int query(int i, int l, int r, int L, int R) {
if (l > R || r < L) return INF;
if (L <= l && r <= R) return T[i];
int m = l + r >> 1;
return min(query(lc, l, m, L, R), query(rc, m + 1, r, L, R));
}

inline int nxt(int x) {
auto it1 = S[a[x]].upper_bound(x), it2 = S[k - a[x]].upper_bound(x);
if (it2 == S[k - a[x]].end()) return n + 1;
else if (it1 == S[a[x]].end()) return *it2;
else if (*it1 < *it2) return n + 1;
else return *it2;
}

inline void solve_1() {
int x, y; cin >> x >> y;

vector<int> vec{ x };

auto it = S[a[x]].lower_bound(x);
if (it != S[a[x]].begin()) vec.push_back(*prev(it));

it = S[k - a[x]].lower_bound(x);
if (it != S[k - a[x]].begin()) vec.push_back(*prev(it));

S[a[x]].erase(x), a[x] = y, S[a[x]].insert(x);

it = S[a[x]].lower_bound(x);
if (it != S[a[x]].begin()) vec.push_back(*prev(it));

it = S[k - a[x]].lower_bound(x);
if (it != S[k - a[x]].begin()) vec.push_back(*prev(it));

for (auto t : vec) update(1, 1, n, t, nxt(t));
}

int lans;
inline void solve_2() {
int x, y; cin >> x >> y; x ^= lans, y ^= lans;
if (query(1, 1, n, x, y) <= y) cout << "Yes" << "\n", ++lans;
else cout << "No" << "\n";
}

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);

cin >> n >> m >> k;
for (int i = 1; i <= n; ++i) cin >> a[i], S[a[i]].insert(i);
for (int i = 1; i <= n; ++i) update(1, 1, n, i, nxt(i));
for (int i = 1; i <= m; ++i) {
int opt; cin >> opt;
if (opt == 1) solve_1();
else solve_2();
}
return 0;
}