题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5919
大意
给定一个长为
n
n
n的数组
a
[
]
a[]
a[],要处理
q
q
q个询问,每个询问给出一个区间
[
l
,
r
]
[l,r]
[l,r],设该区间内共出现了
k
k
k个不同的数,第
i
i
i个数出现的位置为
p
i
p_i
pi(显然
p
1
<
p
2
<
…
…
<
p
k
p_1<p_2<……<p_k
p1<p2<……<pk),输出
p
⌈
k
/
2
⌉
p_{⌈k/2⌉}
p⌈k/2⌉
思路
用主席树,如果将
a
[
]
a[]
a[]按
a
n
、
a
n
−
1
…
…
a
1
a_n、a_{n-1}……a_1
an、an−1……a1的次序插入,插入
a
i
a_i
ai时在当前位置+1,并且若
a
i
a_i
ai不是第一次出现,则在
a
i
a_i
ai上一次出现的位置-1,那么我们就可以在当前的主席树(设为第
i
i
i棵主席树)上查询
[
i
,
j
]
[i,j]
[i,j](
i
<
=
j
<
=
n
i<=j<=n
i<=j<=n)出现的数字数量
k
k
k了,然后只要同样在当前的主席树上查找位置最小的满足出现数量不小于
⌈
k
/
2
⌉
⌈k/2⌉
⌈k/2⌉的位置即可。
查询位置时若左边已存在的数字数量大于或等于目标则直接查询左边,否则查询右边,可以保证时间复杂度是O(
l
o
g
log
log
n
n
n)
因为我是反向插入所以在满足条件时是优先查询右边
int getans(int root,int l,int r,int tz,int l_,int r_)
{
if(l==r)return l;
int mid=(l_+r_)/2;
if(l>mid)return getans(tree[root].rson,l,r,tz,mid+1,r_);
else if(r<=mid)return getans(tree[root].lson,l,r,tz,l_,mid);
else
{
if(tree[tree[root].rson].sum>=tz)return getans(tree[root].rson,mid+1,r,tz,mid+1,r_);
else return getans(tree[root].lson,l,mid,tz-tree[tree[root].rson].sum,l_,mid);
}
}
AC代码
#include<stdio.h>
#include<map>
#include<queue>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
#define MOD 10000000007
#define N 200005
typedef long long LL;
using namespace std;
typedef struct node{
int lson,rson,sum;
}node;
LL tot,n,m,te,len,s,t,k,l,r,l_,r_,ans;
int a[N];
node tree[N*40];
int R[N];
int last[N];
int answer[N];
void init()
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[n-i+1]);
}
}
void insert(int pre,int &root,int l,int r,int val,int l_,int r_)
{
tree[++tot]=tree[pre];root=tot;
tree[root].sum+=val;
if(l_==l&&r_==r)
{
return;
}
int mid=(l_+r_)/2;
if(l>mid) insert(tree[root].rson,tree[root].rson,l,r,val,mid+1,r_);
else if(r<=mid)insert(tree[root].lson,tree[root].lson,l,r,val,l_,mid);
return;
}
int query(int root,int l,int r,int l_,int r_)
{
if(l_==l&&r_==r)return tree[root].sum;
int mid=(l_+r_)/2;
if(l>mid)return query(tree[root].rson,l,r,mid+1,r_);
else return query(tree[root].lson,l,mid,l_,mid)+tree[tree[root].rson].sum;
}
int getans(int root,int l,int r,int tz,int l_,int r_)
{
if(l==r)return l;
int mid=(l_+r_)/2;
if(l>mid)return getans(tree[root].rson,l,r,tz,mid+1,r_);
else if(r<=mid)return getans(tree[root].lson,l,r,tz,l_,mid);
else
{
if(tree[tree[root].rson].sum>=tz)return getans(tree[root].rson,mid+1,r,tz,mid+1,r_);
else return getans(tree[root].lson,l,mid,tz-tree[tree[root].rson].sum,l_,mid);
}
}
int main()
{
scanf("%d",&t);int ct=0;
while(t--)
{
ct++;
scanf("%d%d",&n,&m);
init();
tot=0;
R[0]=0;tree[0].lson=tree[0].rson=tree[0].sum=0;
for(int i=1;i<=n;i++)
{
if(last[a[i]])
{
insert(R[i-1],R[i],last[a[i]],last[a[i]],-1,1,n);
insert(R[i],R[i],i,i,1,1,n);
}else
{
insert(R[i-1],R[i],i,i,1,1,n);
}
last[a[i]]=i;
}
ans=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l_,&r_);
l=min((l_+ans)%n+1,(r_+ans)%n+1);r=max((l_+ans)%n+1,(r_+ans)%n+1);
k=query(R[n-l+1],n-r+1,n,1,n);
ans=getans(R[n-l+1],n-r+1,n-l+1,(k+1)/2,1,n);
ans=n-ans+1;
answer[i]=ans;
}
for(int i=1;i<=n;i++)last[a[i]]=0;
printf("Case #%d:",ct);
for(int i=1;i<=m;i++)printf(" %d",answer[i]);
printf("\n");
}
return 0;
}