1. 程式人生 > 其它 >Educational Codeforces Round 22 E. Army Creation(主席樹)

Educational Codeforces Round 22 E. Army Creation(主席樹)

As you might remember from our previous rounds, Vova really likes computer games. Now he is playing a strategy game known as Rage of Empires.

In the game Vova can hire n different warriors; ith warrior has the type a**i. Vova wants to create a balanced army hiring some subset of warriors. An army is called balanced

if for each type of warrior present in the game there are not more than k warriors of this type in the army. Of course, Vova wants his army to be as large as possible.

To make things more complicated, Vova has to consider q different plans of creating his army. ith plan allows him to hire only warriors whose numbers are not less than l**i

and not greater than r**i.

Help Vova to determine the largest size of a balanced army for each plan.

Be aware that the plans are given in a modified way. See input section for details.

Input

The first line contains two integers n and k (1 ≤ n, k ≤ 100000).

The second line contains n integers a1, a2, ... a**n

(1 ≤ a**i ≤ 100000).

The third line contains one integer q (1 ≤ q ≤ 100000).

Then q lines follow. ith line contains two numbers x**i and y**i which represent ith plan (1 ≤ x**i, y**i ≤ n).

You have to keep track of the answer to the last plan (let's call it last). In the beginning last = 0. Then to restore values of l**i and r**i for the ith plan, you have to do the following:

  1. l**i = ((x**i + last) mod n) + 1;
  2. r**i = ((y**i + last) mod n) + 1;
  3. If l**i > r**i, swap l**i and r**i.

Output

Print q numbers. ith number must be equal to the maximum size of a balanced army when considering ith plan.

Example

input

Copy

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

output

Copy

2
4
1
3
2

題意大概是給定一個數組,每次詢問給一個區間[l, r],對於這個區間的每一類數,如果數量大於k則以k計,數量小於k則正常計,問區間內有多少數。要求強制線上。

對於這個題最關鍵的一點是,如果區間內一個位置pos對於答案有貢獻,設這個位置的數是x,當且僅當所有值為x的位置中在pos前面k個的這個位置比l小。舉例來說,設陣列為[3, 3, 3, 3],k = 2,詢問區間為[1, 3],則第三個3前面k個的位置為1,但是1這個位置不比l小,因此第三個3對於答案沒有貢獻(僅前兩個3有貢獻)。

因此,可以預處理出陣列b,b[i]代表的是i這個位置的數所在的所有位置中,靠前的距離i這個位置為k的那個位置。例如對於樣例[1, 1, 1, 2, 2, 2],對應的b陣列為[0, 0, 1, 0, 0, 4](如果前面沒有k個,直接設定為最小的位置0)。這樣問題就轉化為快速統計[l, r]中b陣列有多少個數小於l。這可以用主席樹來維護。update部分不用更改,僅有每次詢問的部分需要修改一下模版。詳情見程式碼:

#include <iostream>
#include <vector>
#include <cstring>
#define mid (l+r)/2
#define N 100005
#define LOG 20
using namespace std;
int n, k, a[100005], b[100005], q, tot = 0;
vector<int> p[100005];
int T[N], sum[N*LOG], L[N*LOG], R[N*LOG];

inline int build(int l, int r) {
	int rt = ++tot;
	if (l < r){
		L[rt] = build(l, mid);
		R[rt] = build(mid+1, r);
	}
	return rt;
}
inline int update(int pre, int l, int r, int x) {
	int rt = ++tot;
	L[rt] = L[pre]; R[rt] = R[pre]; sum[rt] = sum[pre] + 1; 
	if (l < r){
		if (x <= mid) L[rt] = update(L[pre], l, mid, x);
		else R[rt] = update(R[pre], mid + 1, r, x);
	}
	return rt;
}
inline int query(int u, int v, int l, int r, int k) {
	if (r <= k) return sum[v] - sum[u];
	if(l > k) return 0;
	int ans = 0;
	if (k <= mid) ans = query(L[u], L[v], l, mid, k);
	else ans = query(L[u], L[v], l, mid, k) + query(R[u], R[v], mid + 1, r, k);
	return ans;
}
int main() {
	memset(T, 0, sizeof T); memset(sum, 0, sizeof sum);
	memset(L, 0, sizeof L); memset(R, 0, sizeof R);
	cin >> n >> k;
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		p[a[i]].push_back(i);
		if(p[a[i]].size() > k) {
			b[i] = p[a[i]][p[a[i]].size() - 1 - k];
		} else {
			b[i] = 0;
		}
	}
	T[0] = build(0, 100000);
	for(int i = 1; i <= n; i++) {
		T[i] = update(T[i - 1], 0, 100000, b[i]);
	}

	cin >> q;
	int lst = 0;
	while(q--) {
		int x, y, l, r;
		cin >> x >> y;
		l = (x + lst) % n + 1, r = (y + lst) % n + 1;
		if(l > r) swap(l, r);
		int ans = query(T[l - 1], T[r], 0, 100000, l - 1);
		// 快速統計[l, r]中b陣列有多少個數小於l
		cout << ans << endl;
		lst = ans;
	}
	return 0;
}