zoukankan      html  css  js  c++  java
  • HDU 5919 Sequence II 主席树

    Sequence II




    Problem Description
     
    Mr. Frog has an integer sequence of length n, which can be denoted as a1,a2,,an There are m queries.

    In the i-th query, you are given two integers li and ri. Consider the subsequence ali,ali+1,ali+2,,ari.

    We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as p(i)1,p(i)2,,p(i)ki (in ascending order, i.e.,p(i)1<p(i)2<<p(i)ki).

    Note that ki is the number of different integers in this subsequence. You should output p(i)ki2for the i-th query.
     
    Input
     
    In the first line of input, there is an integer T (T2) denoting the number of test cases.

    Each test case starts with two integers n (n2×105) and m (m2×105). There are n integers in the next line, which indicate the integers in the sequence(i.e., a1,a2,,an,0ai2×105).

    There are two integers li and ri in the following m lines.

    However, Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to li,ri(1lin,1rin). As a result, the problem became more exciting.

    We can denote the answers as ans1,ans2,,ansm. Note that for each test case ans0=0.

    You can get the correct input li,ri from what you read (we denote them as li,ri)by the following formula:
    li=min{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}

    ri=max{(li+ansi1) mod n+1,(ri+ansi1) mod n+1}
     
    Output
     
    You should output one single line for each test case.

    For each test case, output one line “Case #x: p1,p2,,pm”, where x is the case number (starting from 1) and p1,p2,,pm is the answer.
     
    Sample Input
     
    2 5 2 3 3 1 5 4 2 2 4 4 5 2 2 5 2 1 2 2 3 2 4
     
    Sample Output
     
    Case #1: 3 3 Case #2: 3 1
    Hint
     
    题意:
      给定一个序列nn,有mm次查询,每次查询一个区间[l,r][l,r],求区间中每一种数在区间中第一次出现的位置的中位数,强制在线。
    题解:
      强制在线
      利用主席树求区间不同数的个数
      这里有个技巧
      倒着插入主席树
      在寻找位置的中位数上就可以一个log解决了
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    const int N = 2e5 + 10, M = 1e6, mod = 1e9+7, inf = 2e9;
    
    int T,n,q,a[N],l[N*36],r[N*36],v[N*36],sz,root[N],ans[N],last[N];
    
    void update(int x, int &y, int ll, int rr, int k,int c) {
         y = ++sz;
         v[y] = v[x] + c;
         r[y] = r[x];
         l[y] = l[x];
         if(ll == rr) return ;
         int mid = (ll+rr)>>1;
         if(k <= mid) update(l[x], l[y], ll, mid, k,c);
         else update(r[x], r[y], mid + 1, rr, k,c);
    }
    int query(int x,int ll,int rr,int s,int t) {
        if (s <= ll && rr <= t) return v[x];
        int mid = ll + rr >> 1, res = 0;
        if (s <= mid) res += query(l[x], ll, mid, s, t);
        if (t > mid) res += query(r[x], mid + 1, rr, s, t);
        return res;
    }
    
    int finds(int x,int ll,int rr,int k) {
            if(ll == rr) return ll;
            int mid = ll + rr >> 1;
            if(v[l[x]] >= k) return finds(l[x],ll,mid,k);
            else return finds(r[x],mid+1,rr,k-v[l[x]]);
    }
    
    int main() {
            int cas = 0;
            scanf("%d",&T);
            while(T--) {
                scanf("%d%d",&n,&q);
                sz = 0;
                memset(last,0,sizeof(last));
                memset(v,0,sizeof(v));
                memset(l,0,sizeof(l));
                memset(r,0,sizeof(r));
                ans[0] = 0;
                root[n+1] = 0;
                for(int i = 1; i <= n; ++i) scanf("%d",&a[i]);
                for(int i = n; i >= 1; --i) {
                    int x = root[i] = 0;
                    update(root[i+1],x,1,n,i,1);
                    if(last[a[i]]) {
                        update(x,root[i],1,n,last[a[i]],-1);
                    } else root[i] = x;
                    last[a[i]] = i;
                }
                int L,R;
                for(int i = 1; i <= q; ++i) {
                    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 sum = query(root[L],1,n,L,R)  + 1 >> 1;
                    ans[i] = finds(root[L],1,n,sum);
                }
                printf("Case #%d: ",++cas);
                for(int i = 1; i < q; ++i)  printf("%d ",ans[i]);
                cout<<ans[q]<<endl;
            }
            return 0;
    }
  • 相关阅读:
    POJ 3468 A Simple Problem with Integers
    BZOJ 4430 Guessing Camels
    POJ 2309 BST
    POJ 1990 MooFest
    cf 822B Crossword solving
    cf B. Black Square
    cf 828 A. Restaurant Tables
    Codefroces 822C Hacker, pack your bags!
    [HDU 2255] 奔小康赚大钱
    [BZOJ 1735] Muddy Fields
  • 原文地址:https://www.cnblogs.com/zxhl/p/5931224.html
Copyright © 2011-2022 走看看