HDU - 5919 (主席树)

Sequence II

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 4734    Accepted Submission(s): 1329


 

Problem Description

Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,⋯,an There are m queries.

In the i-th query, you are given two integers li and ri. Consider the subsequence ali,ali+1,ali+2,⋯,ari.

We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as p(i)1,p(i)2,⋯,p(i)ki (in ascending order, i.e.,p(i)1<p(i)2<⋯<p(i)ki).

Note that ki is the number of different integers in this subsequence. You should output p(i)⌈ki2⌉for the i-th query.

 

 

Input

In the first line of input, there is an integer T (T≤2) denoting the number of test cases.

Each test case starts with two integers n (n≤2×105) and m (m≤2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,⋯,an,0≤ai≤2×105).

There are two integers li and ri in the following m lines.

However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to l‘i,r‘i(1≤l‘i≤n,1≤r‘i≤n). As a result, the problem became more exciting.

We can denote the answers as ans1,ans2,⋯,ansm. Note that for each test case ans0=0.

You can get the correct input li,ri from what you read (we denote them as l‘i,r‘i)by the following formula:

li=min{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1}

 

ri=max{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1}

 

 

Output

You should output one single line for each test case.

For each test case, output one line “Case #x: p1,p2,⋯,pm”, where x is the case number (starting from 1) and p1,p2,⋯,pm is the answer.

 

 

Sample Input

 

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

 

 

Sample Output

 

Case #1: 3 3 Case #2: 3 1

Hint

 

       给你n(n≤2e5)个数,每个数的大小0<Ai≤2e5。再给你m(m≤2e5)个询问。对于每个询问输入l,r,表示Al...Ar这个区间我们得到每个数第一次出现的位置下标的排列,假设这个区间有k个不同的数,我们得到的每个数第一次出现的位置的排列是p1<p2<p3<...<pk,叫你求第(k+1)/2这个数是多少?

       从右往左建主席树,维护每个数第一次出现的位置,对于每次l,r来说,查询T[l]状态下l,r区间内共有多少个第一次出现的位置,然后查询(sum+1)/2个就行了

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200010;
const int M = MAXN * 40;
int tot, a[MAXN];
int T[M], lson[M], rson[M], c[M];
int build(int l, int r) {
	int root = tot++;
	c[root] = 0;
	if (l != r) {
		int mid = (l + r) >> 1;
		lson[root] = build(l, mid);
		rson[root] = build(mid + 1, r);
	}
	return root;
}
int update(int root, int pos, int val, int m) {
	int newroot = tot++, tmp = newroot;
	c[newroot] = c[root] + val;
	int l = 1, r = m;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (pos <= mid) {
			lson[newroot] = tot++; rson[newroot] = rson[root];
			newroot = lson[newroot]; root = lson[root];
			r = mid;
		}
		else {
			rson[newroot] = tot++; lson[newroot] = lson[root];
			newroot = rson[newroot]; root = rson[root];
			l = mid + 1;
		}
		c[newroot] = c[root] + val;
	}
	return tmp;
}
int query(int root, int l, int r, int k) {
	if (l == r)return l;
	int mid = (l + r) >> 1;
	if (c[lson[root]] >= k) {
		r = mid;
		return query(lson[root], l, r, k);
	}
	else {
		l = mid + 1;
		k -= c[lson[root]];
		return query(rson[root], l, r, k);
	}
}
int querysum(int root, int l, int r, int L, int R) {
	if (L <= l && r <= R) {
		return c[root];
	}
	int mid = (l + r) >> 1, sum = 0;
	if (L <= mid) {
		sum += querysum(lson[root], l, mid, L, R);
	}
	if (R > mid) {
		sum += querysum(rson[root], mid + 1, r, L, R);
	}
	return sum;
}
int pos[MAXN];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int te; cin >> te;
	int cas = 1;
	while (te--) {
		memset(pos, 0, sizeof pos);
		int n, m; cin >> n >> m;
		tot = 0;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		T[n + 1] = build(1, n);
		for (int i = n; i >= 1; i--) {
			T[i] = update(T[i + 1], i, 1, n);
			if (pos[a[i]] != 0)T[i] = update(T[i], pos[a[i]], -1, n);
			pos[a[i]] = i;
		}
		cout << "Case #" << cas << ":";
		int  laans = 0;
		while (m--) {
			int l, r;
			cin >> l >> r;
			l = (l + laans) % n + 1;
			r = (r + laans) % n + 1;
			if (l > r)swap(l, r);
			int k = querysum(T[l], 1, n, l, r);
			k = (k + 1) / 2;
			laans = query(T[l], 1, n, k);
			cout << " " << laans;
		}
		cas++;
		cout << "\n";
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值