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;
    }
  • 相关阅读:
    面试遇到的相关问题
    webpack的学习之旅
    ajax请求数据
    css选择器
    对BFC的理解
    对React的理解
    获取DOM的真实节点
    翻转拼图网页小游戏制作
    acm比赛刷题小技巧
    动态规划 背包九讲的实现。
  • 原文地址:https://www.cnblogs.com/zxhl/p/5931224.html
Copyright © 2011-2022 走看看