题目大意:
给定一个长度为 n n n序列, m m m个询问,每次询问给定一个区间 [ l , r ] [l,r] [l,r],如果这个区间里存在只出现一次的数,输出这个数(如果有多个就输出任意一个),没有就输出0, n , m < = 5 ∗ 1 0 5 n,m<=5*10^5 n,m<=5∗105
输入格式:
第一行一个整数 n n n
接下来1行 n n n个小于 5 ∗ 1 0 5 5*10^5 5∗105的正整数,即序列
下面一行一个整数 m m m
在下面 m m m行,每行两个整数 l , r l,r l,r
输入格式:
共 m m m行,如题目
感谢@守望 提供翻译
You are given an array a a a consisting of n n n integers, and q q q queries to it. i i i -th query is denoted by two integers l i l_i li and r i r_i ri .
For each query, you have to find any integer that occurs exactly once in the subarray of a a a from index l i l_i li to index r i r_i ri (a subarray is a contiguous subsegment of an array).
For example, if a = [ 1 , 1 , 2 , 3 , 2 , 4 ] a = [1, 1, 2, 3, 2, 4] a=[1,1,2,3,2,4] , then for query ( l i = 2 , r i = 6 ) (l_i = 2, r_i = 6) (li=2,ri=6) the subarray we are interested in is [ 1 , 2 , 3 , 2 , 4 ] [1, 2, 3, 2, 4] [1,2,3,2,4] , and possible answers are 1 1 1 , 3 3 3 and 4 4 4 ; for query ( l i = 1 , r i = 2 ) (l_i = 1, r_i = 2) (li=1,ri=2) the subarray we are interested in is [ 1 , 1 ] [1, 1] [1,1] , and there is no such element that occurs exactly once.
Can you answer all of the queries?
The first line contains one integer n n n ( 1 ≤ n ≤ 5 ⋅ 1 0 5 1 \le n \le 5 \cdot 10^5 1≤n≤5⋅105 ).
The second line contains n n n integers a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an ( 1 ≤ a i ≤ 5 ⋅ 1 0 5 1 \le a_i \le 5 \cdot 10^5 1≤ai≤5⋅105 ).
The third line contains one integer q q q ( 1 ≤ q ≤ 5 ⋅ 1 0 5 1 \le q \le 5 \cdot 10^5 1≤q≤5⋅105 ).
Then q q q lines follow, i i i -th line containing two integers l i l_i li and r i r_i ri representing i i i -th query ( 1 ≤ l i ≤ r i ≤ n 1 \le l_i \le r_i \le n 1≤li≤ri≤n ).
Answer the queries as follows:
If there is no integer such that it occurs in the subarray from index l i l_i li to index r i r_i ri exactly once, print 0 0 0 .
Otherwise print any such integer.
6
1 1 2 3 2 4
2
2 6
1 2
4
0
#include
using namespace std;
const int N=1e6+10;
typedef long long ll;
struct modui{
int l,r,id;
}s[N];
ll a[N],c[N],ans[N],stackk[N],id[N],top;
int L=1,R=0,pos[N],n,m,t;
void add(int x){
c[x]++;
//如果该数出现1次进栈放栈顶,并记录该数在栈位置
if(c[x]==1) stackk[++top]=x,id[x]=top;
//如果该数出现2次为不符合时
//通过桶来寻找这个数在栈中的下标,然后把栈顶放入这个位置,再弹出栈顶
if(c[x]==2) stackk[id[x]]=stackk[top],id[stackk[top]]=id[x],stackk[top]=id[x]=0,top--;
return;
}
void del(int x){
c[x]--;
//如果该数出现1次进栈放栈顶,并记录该数在栈位置
if(c[x]==1) stackk[++top]=x,id[x]=top;
//如果该数出现0次为不符合时
//通过桶来寻找这个数在栈中的下标,然后把栈顶放入这个位置,再弹出栈顶
if(c[x]==0) stackk[id[x]]=stackk[top],id[stackk[top]]=id[x],stackk[top]=id[x]=0,top--;
return ;
}
bool cmp(modui x,modui y){//按左端点分块,然后在同一个块当中区间右端点要递增
if (pos[x.l]!=pos[y.l]) return x.l<y.l;
if(pos[x.l]&1) return x.r<y.r;//奇偶性优化
return x.r>y.r;//都是为了加速
}
void query(int l,int r){//移动指针的时候,对应地去删除或添加对答案的贡献
while (L<l) del(a[L++]);//左指针往右移删除
while (L>l) add(a[--L]);//左指针往左移加入
while (R<r) add(a[++R]);//右指针往右移加入
while (R>r) del(a[R--]);//右指针往左移删除
return;
}
int main(){
cin>>n;
int dis=sqrt(n);//块大小
//pos标记每个数所属的分块
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pos[i]=i/dis;
cin>>m;
for(int i=1;i<=m;i++){
scanf("%d %d",&s[i].l,&s[i].r);
s[i].id=i;//排序将会打乱原有的询问顺序,借此离线
}
sort(s+1,s+m+1,cmp);//排序的时候按照左端点所在的块为第一关键字,右端点为第二关键字排序
for(int i=1;i<=m;i++){
query(s[i].l,s[i].r);
ans[s[i].id]=stackk[top];//记录答案
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}