1. 程式人生 > >Sequence II HDU - 5919(主席樹)

Sequence II HDU - 5919(主席樹)

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

In the i-th query, you are given two integers lili and riri. Consider the subsequence ali,ali+1,ali+2,,ariali,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 
p1(i),p2(i),&#x22EF;,pki(i)">p(i)1,p(i)2,,p(i)kip1(i),p2(i),⋯,pki(i) (in ascending order, i.e.,p(i)1<p(i)2<<p(i)kip1(i)<p2(i)<⋯<pki(i)). 

Note that kiki is the number of different integers in this subsequence. You should output 
p&#x2308;ki2&#x2309;(i)">p(i)ki2p⌈ki2⌉(i)for the i-th query.

Input

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

Each test case starts with two integers n (n2×105

n≤2×105) and m (m2×105m≤2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,,an,0ai2×105a1,a2,⋯,an,0≤ai≤2×105). 

There are two integers lili and riri 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 li,ri(1lin,1rin)li‘,ri‘(1≤li‘≤n,1≤ri‘≤n). As a result, the problem became more exciting. 

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

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

li=min{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}li=min{(li‘+ansi−1) mod n+1,(ri‘+ansi−1) mod n+1}


ri=max{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}ri=max{(li‘+ansi−1) mod n+1,(ri‘+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,,pmp1,p2,⋯,pm”, where x is the case number (starting from 1) and p1,p2,,pmp1,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

 給出n個數,然後 m 個查詢,查詢對應區間的不同的數的個數 k, 以及第 (k+1)/2 個數的位置。

正序插入的主席樹可以很容易的求出區間內不同數的個數,但是在求第 (k+1)/2 個數的位置時,由於樹中有 L 之前的資訊,不好直接查詢出。

逆序插入的主席樹和正序一樣,都可以求出區間內不同數的個數,但在求第 (k+1)/2 個數的時候,沒有 L 之前的資訊,所以可以把問題轉換成求這棵樹上第 (k+1)/2 大的位置,就是普通的線段樹了。

 

#include <map>
#include <set>
#include <list>
#include <ctime>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define  lowbit(x)  x & (-x)
#define  mes(a, b)  memset(a, b, sizeof a)
#define  fi         first
#define  se         second
#define  pii        pair<int, int>
#define  INOPEN     freopen("in.txt", "r", stdin)
#define  OUTOPEN    freopen("out.txt", "w", stdout)

typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 2e5 + 10;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;

int n, m;
int cas, tol, T;

struct Node{
	int l, r;
	int cnt;
} node[maxn * 40];
int a[maxn];
int rt[maxn];
int last[maxn];

void init() {
	tol = 0;
	mes(rt, 0);
	mes(last, -1);
}

void update(int l, int r, int &x, int y, int p, int v) {
	x = ++tol;
	node[x] = node[y];
	node[x].cnt += v;
	if(l == r)	return ;
	int mid = l + r >> 1;
	if(p <= mid)
		update(l, mid, node[x].l, node[y].l, p, v);
	else
		update(mid+1, r, node[x].r, node[y].r, p, v);
}

int query_num(int l, int r, int pl, int pr, int rt) {
	if(pl <= l && r <= pr) {
		return node[rt].cnt;
	}
	int mid = l + r >> 1;
	int ans = 0;
	if(pl <= mid)
		ans += query_num(l, mid, pl, pr, node[rt].l);
	if(pr > mid)
		ans += query_num(mid+1, r, pl, pr, node[rt].r);
	return ans;
}

int query_pos(int l, int r, int x, int k) {
	if(l == r)	return l;
	int mid = l + r >> 1;
	int cnt = node[node[x].l].cnt;
	if(k <= cnt)
		return query_pos(l, mid, node[x].l, k);
	else
		return query_pos(mid+1, r, node[x].r, k-cnt);
}

int main() {
	cas = 1;
	scanf("%d", &T);
	while(T--) {
		init();
		scanf("%d%d", &n, &m);
		for(int i=1; i<=n; i++) {
			scanf("%d", &a[i]);
		}
		node[0].cnt = 0;
		for(int i=n; i>=1; i--) {
			if(last[a[i]] == -1) {
				update(1, n, rt[i], rt[i+1], i, 1);
			} else {
				int tmp;
				update(1, n, tmp, rt[i+1], last[a[i]], -1);
				update(1, n, rt[i], tmp, i, 1);
			}
			last[a[i]] = i;
		}
		printf("Case #%d:", cas++);
		int ans = 0;
		while(m--) {
			int l, r;
			scanf("%d%d", &l, &r);
			int tl = min((l+ans)%n+1, (r+ans)%n+1);
			int tr = max((l+ans)%n+1, (r+ans)%n+1);
			int k = query_num(1, n, tl, tr, rt[tl]);
			k = (k + 1) / 2;
			ans = query_pos(1, n, rt[tl], k);
			printf(" %d", ans);
		}
		printf("\n");
	}
	return 0;
}