ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-02-05 19:01:44  阅读:170  来源: 互联网

标签:rt Educational 22 ith Army int army plan Vova


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;
}

标签:rt,Educational,22,ith,Army,int,army,plan,Vova
来源: https://www.cnblogs.com/lipoicyclic/p/15864568.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有