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;
}