HDU 5919 Sequence II(主席树+逆序思想)

Posted Blackops

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 5919 Sequence II(主席树+逆序思想)相关的知识,希望对你有一定的参考价值。

Sequence II

Time Limit: 9000/4500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1422    Accepted Submission(s): 362

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
技术分享

 

题目链接:HDU 5919

区间内的求和+第K小的结合题,难点就在用倒序的方式维护第一次出现的位置,每一颗树都是维护原序列i~n的后缀,从后往前更新的时候把每一个位置都更新掉,这样第一次出现的位置就是最新的位置,然后统计的时候直接统计L~n即可,因为在p序列中L~R与L~n是等效的,后面多出现的无任何影响。

代码:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <bitset>
#include <string>
#include <deque>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=2e5+7;
struct seg
{
    int lson,rson;
    int cnt;
    inline void init()
    {
        lson=rson=cnt=0;
    }
};
seg T[N*40];
int root[N],tot;
int arr[N],ans[N],pre[N];

void init(int n)
{
    CLR(root,0);
    tot=0;
    T[n+1].init();
    ans[0]=0;
    CLR(pre,-1);
}
inline void update(int &cur,int ori,int l,int r,int pos,int v)
{
    cur=++tot;
    T[cur]=T[ori];
    T[cur].cnt+=v;
    if(l==r)
        return ;
    int mid=MID(l,r);
    if(pos<=mid)
        update(T[cur].lson,T[ori].lson,l,mid,pos,v);
    else
        update(T[cur].rson,T[ori].rson,mid+1,r,pos,v);
}
int query(int S,int E,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr)
        return T[E].cnt-T[S].cnt;
    else
    {
        int mid=MID(l,r);
        if(qr<=mid)
            return query(T[S].lson,T[E].lson,l,mid,ql,qr);
        else if(ql>mid)
            return query(T[S].rson,T[E].rson,mid+1,r,ql,qr);
        else
            return query(T[S].lson,T[E].lson,l,mid,ql,mid)+query(T[S].rson,T[E].rson,mid+1,r,mid+1,qr);
    }
}
int findkth(int S,int E,int l,int r,int k)
{
    if(l==r)
        return l;
    else
    {
        int cnt=T[T[E].lson].cnt-T[T[S].lson].cnt;
        int mid=MID(l,r);
        if(k<=cnt)
            return findkth(T[S].lson,T[E].lson,l,mid,k);
        else
            return findkth(T[S].rson,T[E].rson,mid+1,r,k-cnt);
    }
}
int main(void)
{
    int tcase,n,m,i,l,r,L,R;
    scanf("%d",&tcase);
    for (int q=1; q<=tcase; ++q)
    {
        scanf("%d%d",&n,&m);
        init(n);
        for (i=1; i<=n; ++i)
            scanf("%d",&arr[i]);
        int temp_rt=0;
        for (i=1; i<=1; ++i)
        {
            if(pre[arr[i]]==-1)
                update(root[i],root[i+1],1,n,i,1);
            else
            {
                update(temp_rt,root[i+1],1,n,pre[arr[i]],-1);
                update(root[i],temp_rt,1,n,i,1);
            }
            pre[arr[i]]=i;
        }
        for (i=1; i<=m; ++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 D=query(root[n+1],root[L],1,n,L,R);
            ans[i]=findkth(root[n+1],root[L],1,n,(D+1)/2);
        }
        printf("Case #%d:",q);
        for (i=1; i<=m; ++i)
            printf(" %d",ans[i]);
        putchar(‘\n‘);
    }
    return 0;
}

以上是关于HDU 5919 Sequence II(主席树+逆序思想)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 5919 Sequence II(主席树+逆序思想)

HDU 5919 -- Sequence II (主席树)

HDU 5919 Sequence II ( 主席树 )

HDU 5919 Sequence II(主席树)题解

hdu 5919--Sequence II(主席树--求区间不同数个数+区间第k大)

HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)