HDU 5919 Sequence II ( 主席树 )

题意 : 给出 N 个数、然后 M 个问询、问询格式是给出 ( L、R ) 然后需要根据规则变成新的 ( L'、R' ) [ 即此题强制在线了 ]、对于每个问询假设问询区间内有 X 个不同种类的数、每个数从左到右第一次出现的位置是 pos1、pos2... posX 然后要你给出 pos( (X+1)/2 ) 是多少

 

分析 :

主要就是查询区间内不同数的个数、区间内第 K 大

这两个都是主席树的基本功能、所以考虑使用主席树来做

从左到右对于每个前缀可持久化建树、然后对于每个区间问询先查出有多少个不同种类的数

然后再二分位置、把第 (X+1)/2 个找出来就是答案了。

但是二分会多出一个 log 、这里可以有避免二分的办法、需要一个技巧

就是从右往左建树、然后对于问询、就可以直接 log 地查询 K 大值了

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
struct NODE{
    int sum, L, R;
    NODE(){};
    NODE(int _sum, int _L, int _R):
        sum(_sum),L(_L),R(_R){};
}T[maxn*40]; int Tcnt = 0;

int root[maxn];
int arr[maxn], N;

int newNode(int sum, int L, int R)
{
    T[++Tcnt] = NODE(sum, L, R);
    return Tcnt;
}

inline void Insert(int &root, int pre, int pos, int val, int L, int R)
{
    root = newNode(T[pre].sum+val, T[pre].L, T[pre].R);
    if(L == R) return ;
    int M = L + ((R-L)>>1);
    if(pos <= M) Insert(T[root].L, T[pre].L, pos, val, L, M);
    else Insert(T[root].R, T[pre].R, pos, val, M+1, R);
}

int query(int rt, int pos, int L, int R)
{
    if(L == R) return T[rt].sum;
    int ret = 0;
    int M = L + ((R-L)>>1);
    if(pos <= M) ret += query(T[rt].L, pos, L, M);
    else ret += query(T[rt].R, pos, M+1, R) + T[T[rt].L].sum;
    return ret;
}

int Kth(int K, int rt, int l, int r)
{
    if(l == r) return l;
    int m = l + ((r-l)>>1);
    if(T[T[rt].L].sum >= K) return Kth(K, T[rt].L, l, m);
    else return Kth(K-T[T[rt].L].sum, T[rt].R, m+1, r);
}

map<int, int> mp;
int main(void)
{
    int nCase;
    scanf("%d", &nCase);
    for(int Case=1; Case<=nCase; Case++){

        mp.clear();

        printf("Case #%d:", Case);

        T[0] = NODE(0, 0, 0);
        root[N+1] = 0; Tcnt = 0;

        scanf("%d", &N);
        int Q; scanf("%d", &Q);

        for(int i=1; i<=N; i++) scanf("%d", &arr[i]);
        for(int i=N; i>=1; i--){
            if(mp.count(arr[i])){
                int tmpRoot;
                Insert(tmpRoot, root[i+1], i, 1, 1, N);
                Insert(root[i], tmpRoot, mp[arr[i]], -1, 1, N);
            }else Insert(root[i], root[i+1], i, 1, 1, N);
            mp[arr[i]] = i;
        }

        int PreAns = 0;
        while(Q--){
            int l, r;
            scanf("%d %d", &l, &r);
            int A = (l+PreAns)%N+1;
            int B = (r+PreAns)%N+1;
            l = min(A, B);
            r = max(A, B);

            if(l > r) swap(l, r);

            int K = ( query(root[l], r, 1, N) + 1 ) / 2;

////          注释部分为二分写法
//            int L = l, R = r, ans;
//            while(L <= R){
//                int M = L + ((R-L)>>1);
//                if(query(root[l], M, 1, N) >= K) R = M-1, ans = M;
//                else L = M+1;
//            }
//            printf(" %d", PreAns = ans);

            printf(" %d", PreAns = Kth(K, root[l], 1, N));

        }puts("");
    }
    return 0;
}
View Code

 

posted @ 2018-06-11 19:14  qwerity  阅读(144)  评论(0编辑  收藏  举报