HDU 5919 (还算基础的主席树)

来源:互联网 发布:行政审批窗口知乎 编辑:程序博客网 时间:2024/06/05 11:48


                                   Sequence II

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


Problem Description
Mr. Frog has an integer sequence of length n, which can be denoted asa1,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
25 23 3 1 5 42 24 45 22 5 2 1 22 32 4
 

Sample Output
Case #1: 3 3Case #2: 3 1
Hint
题意:
求给定一个区间,在对前边一个答案进行运算后得到一个新的区间,然后问这个区间里面有k个不同的数,把它们第一次出现的位置从小到大排序,问第k/2个位置是什么;
题解:
好像是强制在线,一看要解决的问题,求区间不同数的个数和区间第K大,主席树没跑,因为他要的是第一次出现的位置,我们从后向前插入。
代码:
#include <iostream>#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <map>using namespace std;const int MAX=2e5+500;int a[MAX],root[MAX];map<int,int >mp;struct{    int l,r,sum;} T[MAX*40];int cnt=0;void update(int l,int r,int &x,int y,int pos,int v){    T[++cnt]=T[y];    x=cnt;    T[cnt].sum+=v;    if(l==r)        return ;    int mid=(r+l)>>1;    if(pos<=mid)    {        update(l,mid,T[cnt].l,T[y].l,pos,v);    }    else        update(mid+1,r,T[cnt].r,T[y].r,pos,v);}int query(int rt,int l,int r,int L,int R){    if(L<=l&&R>=r) return T[rt].sum;    int mid=(l+r)>>1;    int ans=0;    if(L<=mid)        ans+=query(T[rt].l,l,mid,L,R);    if(R>mid)        ans+=query(T[rt].r,mid+1,r,L,R);    return ans;}int he(int rt,int l,int r,int k){    if(l==r) return l;    int m=(l+r)>>1;    int tmp=T[T[rt].l].sum;    if(k<=tmp)        return he(T[rt].l,l,m,k);    else        return he(T[rt].r,m+1,r,k-tmp);}void init(){    mp.clear();    cnt=0;//忘记初始化cnt,bug了很长时间。    memset(root,0,sizeof(root));}int main(){    int n,t,q;    int cas=1;    scanf("%d",&t);    while(t--)    {        scanf("%d%d",&n,&q);        for(int i=1; i<=n; i++) scanf("%d",&a[i]);        init();        T[n+1].l=T[n+1].r=T[n+1].sum=0;        for(int i=n; i>=1; i--)        {            if(mp[a[i]]==0)                update(1,n,root[i],root[i+1],i,1);            else            {                int tmp;                update(1,n,tmp,root[i+1],mp[a[i]],-1);                update(1,n,root[i],tmp,i,1);            }            mp[a[i]]=i;        }        printf("Case #%d:",cas++);        int ans=0;        while(q--)        {            int x,y,l,r;            scanf("%d%d",&x,&y);            x=(x+ans)%n+1;            y=(y+ans)%n+1;            l=min(x,y);            r=max(x,y);            int k=(query(root[l],1,n,l,r)+1)>>1;            // cout<<k<<endl;            ans=he(root[l],1,n,k);            printf(" %d",ans);        }        printf("\n");    }    return 0;}



0 0
原创粉丝点击