Sequence II(主席树)
题意:
给定一个长度为的序列和
次询问,每次询问给定一个区间
,求出现的不同数
中,第
个数的位置
题解:
倒序遍历,对每个位置建一棵树,记录每个数字上次出现的位置并更新,那么每次询问就是对第棵树求
区间的和,并求第
大即可,理解清楚本质就是主席树裸题
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
struct node
{
int l, r, sum;
} T[maxn * 50];
int root[maxn], a[maxn], ans[maxn], cnt, pre[maxn];
void init(int rt)
{
cnt = 1;
ans[0] = 0;
memset(root, 0, sizeof(root));
T[rt].l = T[rt].r = T[rt].sum = 0;
memset(pre, 0, sizeof(pre));
}
void update(int l, int r, int &rt, int pos, int val)
{
T[cnt] = T[rt];
rt = cnt++;
T[rt].sum += val;
if (l == r)
return;
int mid = l + r >> 1;
if (pos <= mid)
update(l, mid, T[rt].l, pos, val);
else
update(mid + 1, r, T[rt].r, pos, val);
}
int query(int l, int r, int L, int R, int rt)
{
if (L <= l && r <= R)
return T[rt].sum;
int mid = l + r >> 1;
int ans = 0;
if (L <= mid)
ans += query(l, mid, L, R, T[rt].l);
if (R > mid)
ans += query(mid + 1, r, L, R, T[rt].r);
return ans;
}
int Query(int rt, int l, int r, int k)
{
if (l == r)
return l;
int mid = l + r >> 1;
int sum = T[T[rt].l].sum;
if (sum >= k)
return Query(T[rt].l, l, mid, k);
else
return Query(T[rt].r, mid + 1, r, k - sum);
}
int main()
{
int t, caseN = 0;
scanf("%d", &t);
while (t--)
{
int n, q;
scanf("%d%d", &n, &q);
init(n + 1);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
init(n + 1);
for (int i = n; i >= 1; i--)
{
root[i] = root[i + 1];
if (pre[a[i]])
update(1, n, root[i], pre[a[i]], -1);
update(1, n, root[i], i, 1);
pre[a[i]] = i;
}
for (int i = 1; i <= q; i++)
{
int l, r;
scanf("%d%d", &l, &r);
l = (l + ans[i - 1]) % n + 1;
r = (r + ans[i - 1]) % n + 1;
if (l > r)
swap(l, r);
int k = query(1, n, l, r, root[l]);
k = (k + 1) / 2;
ans[i] = Query(root[l], 1, n, k);
}
printf("Case #%d: ", ++caseN);
for (int i = 1; i <= q; i++)
printf("%d%c", ans[i], i == q ? '\n' : ' ');
}
return 0;
} 
京公网安备 11010502036488号