题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5919
——————————————————————————————————————
Sequence II
Time Limit: 9000/4500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1654 Accepted Submission(s): 420
Problem Description
Mr. Frog has an integer sequence of length n,which can be denoted as
In the
We can denote the positions(the positions according to the original sequence) where an integer appears first in this subsequence as
Note that ki is the number of different integers in this subsequence. You should output p(i)⌈ki2⌉for the i-th query.
Input
In the first line of input,there is an integer T
Each test case starts with two integers n
There are two integers
However,Mr. Frog thought that this problem was too young too simple so he became angry. He modified each query to
We can denote the answers as
You can get the correct input li,ri from what you read (we denote them as
Output
You should output one single line for each test case.
For each test case,output one line “Case #x:
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
————————————————————————————————————————————
题目大意:
给定一个长度为n的序列,然后有m个查询,问你在
解题思路:
因为这个题对
然后他说在询问区间,不相同元素第一次出现的位置的中间那个,
如果是从正序挂到主席树上的话 确实不好维护,
考虑倒叙插入到主席树上,那么每次都只会记录最左边的数,更新的时候如过当前数出现过就删去之前的那个,
就不需要排序过程了,只需要在区间内找第中间的那个就行了
查询的时候我们只要对rt[l]进行查找就行了
于是就变成了找区间内不同数的个数,
然后找区间内第k大的问题,
这样的话就是主席树的基本操作了,
总体复杂度
附本题代码
——————————————————————————————————————————————
#include <bits/stdc++.h>
using namespace std;
/**********************************/
const int N = 2e5+7;
int n,m,ans;
int a[N],vis[N];
void so(int &l,int &r){
int tem=(l+ans)%n+1;
int tmp=(r+ans)%n+1;
l=(tem<tmp)?tem:tmp;
r=(tem>tmp)?tem:tmp;
}
int rt[N],ls[N*40],rs[N*40],sum[N*40],tot;
void build(int& rt,int l,int r){
rt=++tot;
sum[rt]=0;
if(l>=r)return;
int m=((r-l)>>1)+l;
build(ls[rt],l,m);
build(rs[rt],m+1,r);
}
void update(int& rt,int r,int last,int pos,int v){
rt=++tot;
ls[rt]=ls[last];
rs[rt]=rs[last];
sum[rt]=sum[last]+v;
if(l>=r)return;
int m=((r-l)>>1)+l;
if(pos<=m) update(ls[rt],ls[last],pos,v);
else update(rs[rt],r,rs[last],v);
}
int query_num(int rt,int L,int R){
if(L<=l&&r<=R) return sum[rt];
int m=((r-l)>>1)+l;
int ans=0;
if(L<=m) ans+=query_num(ls[rt],L,R);
if(R> m) ans+=query_num(rs[rt],R);
return ans;
}
int query_id(int rt,int k){
if(l>=r)return l;
int m=((r-l)>>1)+l;
int cnt = sum[ls[rt]];
if(k<=cnt) return query_id(ls[rt],k);
else return query_id(rs[rt],k-cnt);
}
int main(){
int _=1,kcase=0;
scanf("%d",&_);
while(_--){
memset(vis,0,sizeof(vis));
ans = 0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
tot = 0;
build(rt[n+1],1,n);
for(int i=n,tem;i;i--){
tem=rt[i+1];
if(vis[a[i]])update(tem,n,rt[i+1],vis[a[i]],-1);
update(rt[i],tem,i,1);
vis[a[i]]=i;
}
printf("Case #%d:",++kcase);
for(int i=1,id;i<=m;i++){
scanf("%d%d",&l,&r);
so(l,r);
// printf("[%d,%d]",r);
id = query_num(rt[l],r);
// printf(" %d<=",id);
id =(id+1)>>1;
ans=query_id(rt[l],id);
printf(" %d",ans);
}
puts("");
}
return 0;
}