问题概述:n个数q次查询,每次查询(l,r)表示查询区间[l,r]内所有不同数字第一次出现的下标,输出这些下标中位数
特殊:如果下标数sum为偶数个,则输出第sum/2个下标,且强制在线,每一组的l和r都跟上一组的答案有关
输入样例: 对应输出:
1 Case #1: 3 1
5 2
2 5 2 1 2
2 3
2 4
解题思路:
将数组倒过来建树,每当添加一个数字时,设这个数字的下标为i,这个数字上次出现的下标为j,则下标i对应
的val值+1,下标j对应的val值-1,每次查询区间[l,r]直接询问版本为l的树即可,先找出在这个区间内的val值之和
sum,然后在这个区间内找到第(sum+1)/2个值为1的下标就是答案
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef struct
{
int l, r;
int val;
}Ctree;
Ctree s[8000005];
int n, tot, a[200005], t[200005], flag[200005], prt[200005];
int Build(int l, int r);
int Update(int root, int x, int k);
int Query(int root, int l, int r, int a, int b);
int Find(int root, int k);
int main(void)
{
int T, i, q, l, r, ans, sum, k, temp, cas = 1;
scanf("%d", &T);
while(T--)
{
ans = tot = 0;
memset(flag, -1, sizeof(flag));
scanf("%d%d", &n, &q);
for(i=1;i<=n;i++)
scanf("%d", &a[i]);
t[n+1] = Build(1, n);
for(i=n;i>=1;i--)
{
t[i] = Update(t[i+1], i, 1);
if(flag[a[i]]!=-1)
t[i] = Update(t[i], flag[a[i]], -1); /*直接另起一棵树,虽然有点浪费空间*/
flag[a[i]] = i;
}
k = 0;
while(q--)
{
scanf("%d%d", &l, &r);
temp = l;
l = min((l+ans)%n+1, (r+ans)%n+1);
r = max((temp+ans)%n+1, (r+ans)%n+1);
sum = Query(t[l], 1, n, l, r);
ans = Find(t[l], (sum+1)/2);
prt[++k] = ans;
}
printf("Case #%d:", cas++);
for(i=1;i<=k;i++)
printf(" %d", prt[i]);
printf("\n");
}
return 0;
}
int Build(int l, int r) /*建空树,所有节点val值为0*/
{
int m, root;
m = (l+r)/2;
root = ++tot;
if(l==r)
{
s[root].val = 0;
return root;
}
s[root].l = Build(l, m);
s[root].r = Build(m+1, r);
s[root].val = s[s[root].l].val+s[s[root].r].val;
return root;
}
int Update(int root, int x, int k) /*修改第x个下标的值*/
{
int now, temp, m, l, r;
temp = now = ++tot;
l = 1, r = n;
while(l<r)
{
m = (l+r)/2;
s[now].val = s[root].val+k;
if(x<=m)
{
s[now].l = ++tot;
s[now].r = s[root].r;
root = s[root].l;
r = m;
now = tot;
}
else
{
s[now].l = s[root].l;
s[now].r = ++tot;
root = s[root].r;
l = m+1;
now = tot;
}
}
s[now].val = s[root].val+k;
return temp;
}
int Query(int root, int l, int r, int a, int b)
{
int m, sum;
if(l>=a && r<=b)
return s[root].val;
m = (l+r)/2;
sum = 0;
if(a<=m)
sum += Query(s[root].l, l, m, a, b);
if(b>=m+1)
sum += Query(s[root].r, m+1, r, a, b);
return sum;
}
int Find(int root, int k)
{
int l, r, m;
l = 1, r = n;
while(l<r)
{
m = (l+r)/2;
if(s[s[root].l].val>=k)
{
root = s[root].l;
r = m;
}
else
{
k -= s[s[root].l].val;
root = s[root].r;
l = m+1;
}
}
return l;
}