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 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(i)⌈ki2⌉p⌈ki2⌉(i)for the i-th query.


Input

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

Each test case starts with two integers n (n≤2×105n≤2×105) and m (m≤2×105m≤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×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 l‘i,r‘i(1≤l‘i≤n,1≤r‘i≤n)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 l‘i,r‘ili‘,ri‘)by the following formula:

li=min{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) mod n+1}li=min{(li‘+ansi−1) mod n+1,(ri‘+ansi−1) mod n+1}
ri=max{(l‘i+ansi−1) mod n+1,(r‘i+ansi−1) 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;
}

  

上一篇:C++string的操作


下一篇:MySQL系列之七:主从复制(转)