首页 > 代码库 > HDU 5919 -- Sequence II (主席树)

HDU 5919 -- Sequence II (主席树)

 题意:

给一串数字,每个数字的位置是这个数第一次出现的位置。

每个询问对于序列的一个子区间,设一共有k个不同的数,求第ceil(k/2)个数的位置。

因为强制在线,所以离线乱搞pass掉。

主席树可解。

 

考虑一个数列:

p      1 2 3 4 5 6  // 原序列标号

a : 1 2 1 2 3 4  // 原序列

p1  1 2 1 2 5 6  // 子序列开始下标为1

p2        2 3 1 5 6

p3           3 4 5 6

p4              4 5 6

p5                 5 6

p6                    6

有一个规律就是对于以L为开始的子序列来说,只要求出[L, N]的子区间,R是不影响P(L)数组的。

那么就想到将数组倒过来建主席树。

树里存的是什么呢????

存的是…【此处想了10分钟……】…区间内不同数的个数(只考虑第一次出现的)

那么在用一个数组记录每个数第一个出现的位置,每添加一个数,该位置+1,如果一个数之前出现过,那么就要更改之前第一次出现的位置-1。

不是很会主席树,之前就写过一道模板题= =  强行没看题解,一顿乱搞还是搞出来了,但是估计写的很麻烦

技术分享

 

 

#include <bits/stdc++.h>using namespace std;const int N = 200005;struct node {    int l, r, v;} T[N*40];int a[N];int pos[N];int root[N], cnt;int ans;// y is x previous versionvoid update(int l, int r, int &x, int y, int p, int v) {    T[++cnt] = T[y], T[cnt].v += v; x = cnt;    if (l == r) return ;    int mid = (l+r) >> 1;    if (mid >= p) update(l, mid, T[x].l, T[y].l, p, v);    else update(mid+1, r, T[x].r, T[y].r, p, v);}// p1 > p2void update(int l, int r, int &x, int y, int p1, int v1, int p2, int v2) {    T[++cnt] = T[y]; x = cnt;    if (l == r) return ;    int mid = (l+r) >> 1;    // three conditions    // p1 > mid >= p2,  p1 > p2 > mid,  mid >= p1 > p2    if (p1 > mid && p2 <= mid) {        update(mid+1, r, T[x].r, T[y].r, p1, v1);        update(l, mid, T[x].l, T[y].l, p2, v2);    } else if (p2 > mid) {        update(mid+1, r, T[x].r, T[y].r, p1, v1, p2, v2);    } else {        update(l, mid, T[x].l, T[y].l, p1, v1, p2, v2);    }}void query(int l, int r, int x, int k) {    if (l == r) {        ans = l; return ;    }    int mid = (l+r) >> 1;    if (T[T[x].r].v >= k) {        ans = mid+1;        query(mid+1, r, T[x].r, k);    } else {        query(l, mid, T[x].l, k-T[T[x].r].v);    }}int query(int l, int r, int x, int L, int R) {    if (l >= L && r <= R) return T[x].v;    int mid = (l+r) >> 1;    int ans = 0;    if (mid >= L) ans += query(l, mid, T[x].l, L, R);    if (mid < R) ans += query(mid+1, r, T[x].r, L, R);    return ans;}int main(){    //freopen("in.txt", "r", stdin);    int t, cas = 0;    scanf("%d", &t);    while (t--) {        printf("Case #%d:", ++cas);        ans = 0;        int n, q, l_, r_, l, r, k;        scanf("%d%d", &n, &q);        memset(pos, 0, sizeof pos); cnt = 0;        for (int i = 1; i <= n; ++i) scanf("%d", &a[n-i+1]);        for (int i = 1; i <= n; ++i) {            if (pos[a[i]]) update(1, n, root[i], root[i-1], i, 1, pos[a[i]], -1);            else update(1, n, root[i], root[i-1], i, 1);            pos[a[i]] = i;        }        while (q--) {            scanf("%d%d", &l_, &r_);            l_ = (l_ + ans) % n + 1;            r_ = (r_ + ans) % n + 1;            l = min(l_, r_);            r = max(l_, r_);            l = n-l+1, r = n-r+1; swap(l, r);            k = query(1, n, root[r], l, r);            query(1, n, root[r], ceil(k/2.0));            ans = n-ans+1;            printf(" %d", ans);        }        printf("\n");    }    return 0;}

 

HDU 5919 -- Sequence II (主席树)