Yunli’s Subarray Queries (easy version)
#莫队 #数据结构
题目描述
This is the easy version of the problem. In this version, it is guaranteed that r = l + k − 1 r=l+k-1 r=l+k−1 for all queries.
For an arbitrary array b b b, Yunli can perform the following operation any number of times:
- Select an index i i i. Set b i = x b_i = x bi=x where x x x is any integer she desires ( x x x is not limited to the interval [ 1 , n ] [1,n] [1,n]).
Denote f ( b ) f(b) f(b) as the minimum number of operations she needs to perform until there exists a consecutive subarray ∗ ^{\text{∗}} ∗ of length at least k k k in b b b.
Yunli is given an array a a a of size n n n and asks you q q q queries. In each query, you must output ∑ j = l + k − 1 r f ( [ a l , a l + 1 , … , a j ] ) \sum_{j=l+k-1}^{r} f([a_l, a_{l+1}, \ldots, a_j]) ∑j=l+k−1rf([al,al+1,…,aj]). Note that in this version, you are only required to output f ( [ a l , a l + 1 , … , a l + k − 1 ] ) f([a_l, a_{l+1}, \ldots, a_{l+k-1}]) f([al,al+1,…,al+k−1]).
∗ ^{\text{∗}} ∗If there exists a consecutive subarray of length k k k that starts at index i i i ( 1 ≤ i ≤ ∣ b ∣ − k + 1 1 \leq i \leq |b|-k+1 1≤i≤∣b∣−k+1), then b j = b j − 1 + 1 b_j = b_{j-1} + 1 bj=bj−1+1 for all i ≤ ; j ≤ i + k − 1 i \leq; j \leq i+k-1 i≤;j≤i+k−1.
输入格式
The first line contains t t t ( 1 ≤ t ≤ 1 0 4 1 \leq t \leq 10^4 1≤t≤104) — the number of test cases. The first line of each test case contains three integers n n n, k k k, and q q q ( 1 ≤ k ≤ n ≤ 2 ⋅ 1 0 5 1 \leq k \leq n \leq 2 \cdot 10^5 1≤k≤n≤2⋅105, 1 ≤ q ≤ 2 ⋅ 1 0 5 1 \leq q \leq 2 \cdot 10^5 1≤q≤2⋅105) — the length of the array, the length of the consecutive subarray, and the number of queries. The following line contains n n n integers a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an ( 1 ≤ a i ≤ n 1 \leq a_i \leq n 1≤ai≤n). The following q q q lines contain two integers l l l and r r r ( 1 ≤ l ≤ r ≤ n 1 \leq l \leq r \leq n 1≤l≤r≤n, r = l + k − 1 r=l+k-1 r=l+k−1) — the bounds of the query. It is guaranteed that the sum of n n n over all test cases does not exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105 and the sum of q q q over all test cases does not exceed 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105.
输出格式
Output ∑ j = l + k − 1 r f ( [ a l , a l + 1 , … , a j ] ) \sum_{j=l+k-1}^{r} f([a_l, a_{l+1}, \ldots, a_j]) ∑j=l+k−1rf([al,al+1,…,aj]) for each query on a new line.
样例 #1
样例输入 #1
3
7 5 3
1 2 3 2 1 2 3
1 5
2 6
3 7
8 4 2
4 3 1 1 2 4 3 2
3 6
2 5
5 4 2
4 5 1 2 3
1 4
2 5
样例输出 #1
2
3
2
2
2
2
1
解法
解题思路
E a s y Easy Easy版本的窗口大小是固定的,也就是每次给定一个固定的窗口大小和起点,找最小需要被修改的次数,使其内部完全都是连续的 k k k个数。
首先,如何判断窗口内的每个数是否是连续递增的,且相差为 1 1 1呢?
例如以下的数列:
[
1
,
2
,
5
,
6
,
7
,
8
,
9
]
[1,2,5,6,7,8,9]
[1,2,5,6,7,8,9]
可以发现,对于这个窗口 [ 1 , 2 ] [1,2] [1,2]是连续的 [ 5 , 6 , 7 , 8 , 9 ] [5,6,7,8,9] [5,6,7,8,9]也是连续的,它们的值-下标的大小是一样的,比如前者是 0 0 0,后者是 2 2 2。 这样问题就迎刃而解了,我们只需要维护这个窗口中出现最多的那个数的次数,然后用窗口大小减去这个次数,就是要修改的最少次数了。
而对于多个询问,而不存在修改的问题,我们容易想到使用莫队算法来离线处理,当指针移动的时候就使用上述的方法来维护一个存放出现次数的 m u t i s e t mutiset mutiset,每次更新答案即可。
代码
int n, m, k, len;
struct node {
int l, r, id;
bool operator<(node& x) {
if ((l - 1) / len + 1 != (x.l - 1) / len + 1) return l < x.l;
if (((l - 1) / len + 1) & 1) return r < x.r;
else return r > x.r;
}
}q[N];
void solve() {
cin >> n >> k >> m;
len = sqrt(m);
vector<int>a(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
for (int i = 1; i <= m; ++i) {
int l, r;
cin >> l >> r;
q[i] = { l,r,i };
}
map<int, int>mp;
multiset<int>mst;
sort(q + 1, q + 1 + m);
auto add = [&](int idx)->void {
mst.extract(mp[a[idx] - idx]);
mp[a[idx] - idx]++;
mst.insert(mp[a[idx] - idx]);
};
auto del = [&](int idx)->void {
mst.extract(mp[a[idx] - idx]);
mp[a[idx] - idx]--;
mst.insert(mp[a[idx] - idx]);
};
int l = 1, r = 0;
vector<int>res(m + 1);
for (int i = 1; i <= m; ++i) {
while (l > q[i].l) add(--l);
while (l < q[i].l) del(l++);
while (r < q[i].r) add(++r);
while (r > q[i].r) del(r--);
res[q[i].id] = k - *mst.rbegin();
}
for (int i = 1; i <= m; ++i) {
std::cout << res[i] << "\n";
q[i] = { 0,0,0 };
}
}
signed main() {
ios::sync_with_stdio(0);
std::cin.tie(0);
std::cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
};