zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    求求你,快去学习吧!!
    研究生英语读写译----topic3
    SQL----where 和 on 的区别
    SQL----语句执行顺序
    SQL----Inner Join、 Outer Join、Cross Join理解
    将一般的数值转换为金额格式(分隔千分位和自动增加小数点)
    伪元素 before 和 after 各种妙用
    抽空笑一笑
    别笑抽咯
    JavaScript继承方式详解
  • 原文地址:https://www.cnblogs.com/qwertiLH/p/9168639.html
Copyright © 2011-2022 走看看