[HDU 5919] Sequence II (主席树)

链接

HDU 5919


题意

CCPC的I题。

给出一个序列,问区间[l, r]中所有不同元素出现的第一个位置(取最左)组成的序列中的中位数。
第i个询问区间依赖于第i-1个询问的答案,所以是强制在线的。


题解

比较经典的主席树维护区间种类问题的变形。

相同元素只取最左侧位置,所以对序列a,从a[n]到a[1]建立主席树,插入新元素到主席树中时取消相同元素的贡献,只保留最左侧元素。
查询[l, r]的时候,查询第l个版本的主席树就好,复杂度O(nlogn)。

这里需要注意一下(其实是主席树基本用法需要注意的东西),当对某版本进行多次单点更新的时候,每次都需要新增一条路径,必须保证不对以往的版本造成影响。


代码

#include 
#include 
#include 
#include 
using namespace std;
#define maxn (200010)
int root[maxn], tot;
struct seg {
    int lson, rson, val;
} T[maxn * 40];
void update(int l, int r, int &now, int pre, int i, int val)
{
    int tmp = now;
    now = ++tot;
    T[now] = tmp ? T[tmp] : T[pre];
    T[now].val += val;

    if(l == r) return ;
    int m = (l + r) >> 1;
    if(i <= m) update(l, m, T[now].lson, T[pre].lson, i, val);
    else update(m + 1, r, T[now].rson, T[pre].rson, i, val);
}
int query(int l, int r, int now, int K)
{
    if(l == r) return r;
    int m = (l + r) >> 1;
    if(T[T[now].lson].val >= K)
        return query(l, m, T[now].lson, K);
    else
        return query(m + 1, r, T[now].rson, K - T[T[now].lson].val);
}
int getsum(int l, int r, int now, int L, int R)
{
    if(L <= l && r <= R) return T[now].val;
    int m = (l + r) >> 1, ret = 0;
    if(L <= m) ret += getsum(l, m, T[now].lson, L, R);
    if(R > m) ret += getsum(m + 1, r, T[now].rson, L, R);
    return ret;
}
int a[maxn], p[maxn];
int main()
{
    int t, kase = 0;
    cin >> t;
    while(t--)
    {
        int n, m;
        cin >> n >> m;

        for(int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        for(int i = n; i >= 1; i--)
        {
            if(p[a[i]]) update(1, n, root[i], root[i+1], p[a[i]], -1);
            update(1, n, root[i], root[i+1], i, 1);
            p[a[i]] = i;
        }
        printf("Case #%d:", ++kase);
        for(int i = 0, l, r, ans = 0, sum; i < m; i++)
        {
            scanf("%d%d", &l, &r);
            l = (l + ans) % n + 1;
            r = (r + ans) % n + 1;
            if(l > r) swap(l, r);
            sum = getsum(1, n, root[l], l, r);
            sum = sum / 2 + sum % 2;
            ans = query(1, n, root[l], sum);
            printf(" %d", ans);
        }
        printf("\n");
        while(tot)
        {
            T[tot].lson = T[tot].rson = 0;
            T[tot--].val = 0;
        }
        for(int i = 1; i <= n; i++)
        {
            root[i] = 0;
            p[a[i]] = 0;
        }
        tot = 0;
    }
    return 0;
}

运行结果

你可能感兴趣的:([HDU 5919] Sequence II (主席树))