给你一个含有n个数的数列,m次查询。每次查询给出l和r两个数,表示子序列a[l]…a[r],然后子序列中有k种数(需要自己求出k值),
p[j]表示第j种数从左到右第一次出现的位置,那么会得到p[1]…p[k] && p[1] < p[2] < … < p[k]。然后倒着建立主席树,然后就类似区间k小的查找。
O(n∗logn+n∗logn+q∗(logn+logn))
#include <stdio.h>
#define min(x, y) x > y ? y : x;
#define max(x, y) x > y ? x : y;
int nCase = 0;
#define maxn 410000
int ls[maxn*20], rs[maxn*20], root[maxn];
int sum[maxn*20];
int tot;
void init() {
tot = 0;
}
void build(int *rt, int l, int r) {
*rt = ++tot;
sum[*rt] = 0;
if (l == r) return ;
int mid = (l + r) >> 1;
build(&ls[*rt], l, mid);
build(&rs[*rt], mid + 1, r);
}
void updata(int last, int *rt, int l, int r, int pos, int val) {
*rt = ++tot;
sum[*rt] = sum[last] + val;
ls[*rt] = ls[last];
rs[*rt] = rs[last];
if (l == r) return ;
int mid = (l + r) >> 1;
if (pos <= mid) updata(ls[last], &ls[*rt], l, mid, pos, val);
else updata(rs[last], &rs[*rt], mid + 1, r, pos, val);
}
int res;
int find(int rt, int l, int r, int pos) {
res = 0;
int mid;
while(l <= r) {
mid = (l + r) >> 1;
if (r == pos) {res += sum[rt];break;}
if (mid == pos) {
res += sum[ls[rt]];
break;
}
if (pos <= mid) {
rt = ls[rt];
r = mid;
}else {
res += sum[ls[rt]];
rt = rs[rt];
l = mid + 1;
}
}
return res;
}
int get(int rt, int l, int r, int pos, int k) {
int mid;
while(l < r) {
mid = (l + r) >> 1;
if (pos <= mid) {
rt = ls[rt];
r = mid;
}else {
if (sum[ls[rt]] >= k) {
rt = ls[rt];
r = mid;
}else {
k -= sum[ls[rt]];
rt = rs[rt];
l = mid + 1;
}
}
}
return l;
}
int a[maxn];
int ans[maxn];
int mp[maxn];
int kase;
int l, r, ll, rr, k, low, high, p;
int n, q, i;
int main(int argc, const char * argv[])
{
scanf("%d", &kase);
while(kase--) {
scanf("%d%d", &n, &q);
for (i = 1;i <= n;++i){ scanf("%d", &a[i]);mp[a[i]] = 0;}
init();
build(&root[n + 1], 1, n);
for (i = n;i >= 1;--i) {
if (mp[a[i]] == 0) updata(root[i + 1], &root[i], 1, n, i, 1);
else {
int temp;
updata(root[i + 1], &temp, 1, n, mp[a[i]], -1);
updata(temp, &root[i], 1, n, i, 1);
}
mp[a[i]] = i;
}
printf("Case #%d:", ++nCase);
ans[0] = 0;
for (i = 1;i <= q;++i) {
scanf("%d%d", &l, &r);
ll = min((l + ans[i - 1]) % n + 1, (r + ans[i - 1]) % n + 1);
rr = max((l + ans[i - 1]) % n + 1, (r + ans[i - 1]) % n + 1);
l = ll, r = rr;
k = find(root[l], 1, n, r);
if (k & 1) k = k / 2 + 1;
else k = k / 2;
p = get(root[l], 1, n, r, k);/*类似k小的查找*/
/*也可以二分求p值*/
ans[i] = p;
printf(" %d", p);
}
puts("");
}
return 0;
}