http://codeforces.com/problemset/problem/1000/F
You are given an array aa consisting of nn integers, and qq queries to it. ii -th query is denoted by two integers lili and riri . For each query, you have to find any integer that occurs exactly once in the subarray of aa from index lili to index riri (a subarray is a contiguous subsegment of an array). For example, if a=[1,1,2,3,2,4] , then for query (li=2,ri=6) the subarray we are interested in is [1,2,3,2,4] , and possible answers are 1 , 3 and 4 ; for query (li=1,ri=2) the subarray we are interested in is [1,1], and there is no such element that occurs exactly once.
Can you answer all of the queries?
Input
The first line contains one integer n (1≤n≤5⋅10^5 ).
The second line contains nn integers a1,a2,…,an (1≤ai≤5⋅10^5).
The third line contains one integer q (1≤q≤5⋅10^5).
Then qq lines follow, ii -th line containing two integers lili and riri representing ii -th query (1≤li≤ri≤n).
Output
Answer the queries as follows:
If there is no integer such that it occurs in the subarray from index lili to index riri exactly once, print 00 . Otherwise print any such integer.
Example
Input
6
1 1 2 3 2 4
2
2 6
1 2
Output
4
0
题目大意:给出n个数字,要查询m次,对每次查询若区间[l,r]内存在一个数在该区间内只出现了一次,则输出该数(有多个则输出任意一个)否则输出0。
思路:这道题好难啊,一直没有什么很好的思路,看了别人的代码也是一知半解的,写了好久终于写出来了orz。基本思路就是用pos[i]存储i上一次出现的位置,那么对于区间[l,r],若其中的某个元素a[i]满足pos[a[i]]<l,那么这个a[i]必定是满足题意的,若没有元素满足这个条件,那么就记为0。因此,我们的想法就是维护所有满足pos[a[i]]<l的pos[a[i]]的最小值。此外我们很容易发现,当一个元素在该序列中已经出现过的时候,对后续的维护是有影响的,比如:a[1]=1,a[2]=1,那么我们容易得到:[1,1]的答案是1;[2,2]的答案是1;但是[1,2]的答案是0,因为在区间[1,2]内,pos[1]=1,即元素1上一次出现的位置是1,而该区间左端点也是1,显然1<1不成立。由此我们可以看出,pos[i]记录的是上一次i出现的位置,对于上上次或者更靠前出现的位置对我们没有用处,但是不处理的话,会影响后续的维护,前面已经说过了,维护的是满足题意的元素的位置的最小值,按照这个逻辑,我们应该取min(0,1) (分别对应上上次出现和上一次出现的位置),又0<1,这就推出了矛盾。因此我们必须对以前已经出现过的元素进行处理,怎么处理呢,我们把它的距离修改成INF即可(因为取的是最小值嘛 这个这么大不会选它的 这个操作是对线段树的叶子节点进行的 因为维护操作是线段树在做),只要这个元素以前出现过,现在又出现了,就要进行处理(很容易理解 对于区间[l,r] 若其左区间位置i元素为k 右区间位置j元素也为k 因为这个操作使线段树[i,i]叶子节点的距离变成INF 那么对该区间进行pushup操作时 必定不会选k)。也正是这个原因,导致我们必须从左到右处理序列,因此要进行离线操作,即把查询按照右区间排序。思路大概就是这样,具体的实现就看代码吧。我这里线段树维护是一个pair<int,int> p,p.second(后者)代表元素,p.first(前者)代表该元素在序列中上一次出现的位置,两个pair类型的比较会先比较前者即先比较位置,因此维护的依然是位置的最小值。(确实有点难理解 要多思考多想想 代码的注释也比较详细 毕竟好几个小时才做出来 还是认真对待吧)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
const int maxn=500005;
struct qry//查询
{
int l,r,id;//查询区间的左右端点以及编号
bool operator < (const qry &a)const//右端点排序
{
if(r==a.r)
return l<a.l;
return r<a.r;
}
};
struct node//线段树节点
{
int l,r;//左右端点
pair<int,int> p;//位置 数字
};
qry ask[maxn];//查询
node tree[maxn<<2];//线段树
int a[maxn];//数字序列
int pos[maxn];//pos[i]记录i上一次出现的位置
int re[maxn];//记录最终结果
void build(int i,int l,int r)//建树
{
tree[i].l=l;
tree[i].r=r;
if(l==r)
return ;
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
}
void update(int i,int t,int p,int n)//i:节点编号 t:位置 p:上一次出现的位置 n:数字
{
if(tree[i].l==tree[i].r&&tree[i].l==t)//单点修改
{
tree[i].p=pair<int,int>(p,n);
return ;
}
int mid=(tree[i].l+tree[i].r)>>1;
if(t<=mid)
update(i<<1,t,p,n);
else
update(i<<1|1,t,p,n);
tree[i].p=min(tree[i<<1].p,tree[i<<1|1].p);//维护位置的最小值
}
pair<int,int> query(int i,int l,int r)//区间查询 返回的是pair类型
{
if(tree[i].l==l&&tree[i].r==r)
return tree[i].p;
int mid=(tree[i].l+tree[i].r)>>1;
if(r<=mid)
return query(i<<1,l,r);
else if(l>mid)
return query(i<<1|1,l,r);
else
return min(query(i<<1,l,mid),query(i<<1|1,mid+1,r));
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int m;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d %d",&ask[i].l,&ask[i].r);
ask[i].id=i;
}
sort(ask,ask+m);//排序 离线操作
build(1,1,n);//建树
int s=1;//当前要处理第s个元素
for(int i=0;i<m;i++)//m次查询
{
while(s<=ask[i].r)//处理到当前查询的右端点为止
{
if(pos[a[s]])//a[s]以前出现过 pos[a[s]]是a[s]上次出现的位置
update(1,pos[a[s]],INF,a[s]);//把上次出现的位置 置为INF
//(注意:update修改的是线段树的东西 并没有修改pos数组)
update(1,s,pos[a[s]],a[s]);//更新操作 s:a[s]当前的位置 pos[a[s]]:a[s]上次出现的位置
pos[a[s]]=s;//更新pos数组
s++;
}
pair<int,int> tp=query(1,ask[i].l,ask[i].r);
if(tp.first<ask[i].l)//位置最小值 小于该查询区间的左端点 满足题意
re[ask[i].id]=tp.second;
}
for(int i=0;i<m;i++)
printf("%d\n",re[i]);
return 0;
}