欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CodeForces 1000F One Occurrence( 离线处理+线段树解法)

程序员文章站 2022-05-27 16:46:36
...

F. One Occurrence
time limit per test:3 seconds
memory limit per test:768 megabytes
input:standard input
output:standard output

You are given an array a consisting of n integers, and q queries to it. i-th query is denoted by two integers li and ri. For each query, you have to find any integer that occurs exactly once in the subarray of a from index li to index ri (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(1n5105).

The second line contains n integers a1,a2,,an (1ai5105).

The third line contains one integer q(1q5105).

Then q lines follow, i-th line containing two integers li and ri representing i-th query (1lirin).

Output

Answer the queries as follows:

If there is no integer such that it occurs in the subarray from index li to index ri exactly once, print 0. Otherwise print any such integer.

Example
Input
Copy
6
1 1 2 3 2 4
2
2 6
1 2
Output
Copy
4
0


        大致题意:给你一个固定的数列a,然后q个询问,每个询问给出一个区间,问你区间内是否有恰好出现一次的数字,如果有输出任意一个,否则输出0。

        这题主要方法就是仿照17年HDU多校有一道题的做法,HDU 6070。其实也只是用了其中的一个思想,也即用每一个数字把区间分段。对于每一个区间[1,r]中的最右边的一个数字i,我都可以记录一个pos[i],表示数字i在区间[1,r]中上一个出现的位置。这里最右边指的是,同一个数字i,可能在区间中出现多次,最后那次是我们想要的。求出了这个pos,我们可以发现,对于一个询问[l,r],如果区间中所有有效的pos的数值的最小值小于l,那么可以说明存在一个数字x,在区间里面出现过,而且他上一次出现的位置是在区间外面,这个数字就是答案。

        显然,我们可以看出,这个最右边是与这个r的选取有关。所以我们得顺序枚举这个r,同时对询问按照右端点进行排序,离线处理。但是从r更新到r+1的时候要注意,如果a[r+1]之前出现过,那么他的上一次出现位置就是pos[a[r]],我们把树中位置r更新为pos[a[r]]的同时,别忘了要把位置pos[a[r]]的数值消除。由于只是求最小值,所以把位置pos[a[r]]的数值变成INF即可。具体见代码:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 500010

using namespace std;

struct query{int l,r,id;} Q[N];
int n,q,a[N],pos[N],ans[N];
typedef pair<int,int> PII;

struct ST
{
	struct node{int l,r;PII min;} tree[N<<2];

	inline void build(int i,int l,int r)
	{
		tree[i].r=r;
		tree[i].l=l;
		if (l==r) return;
		int mid=(l+r)>>1;
		build(i<<1,l,mid);
		build(i<<1|1,mid+1,r);
	}

	inline void update(int i,int pos,int pre)
	{
		if (tree[i].l==tree[i].r)
		{
			tree[i].min=PII(pre,pos);
			return;
		}
		int mid=(tree[i].l+tree[i].r)>>1;
		if (mid>=pos) update(i<<1,pos,pre);
		else if (mid<pos) update(i<<1|1,pos,pre);
		tree[i].min=min(tree[i<<1].min,tree[i<<1|1].min);
	}

	inline PII getmin(int i,int l,int r)
	{
		if (tree[i].l==l&&tree[i].r==r) return tree[i].min;
		int mid=(tree[i].l+tree[i].r)>>1;
		if (mid>=r) return getmin(i<<1,l,r);
		else if (mid<l) return getmin(i<<1|1,l,r);
		else return min(getmin(i<<1,l,mid),getmin(i<<1|1,mid+1,r));
	}

} seg;

bool cmp(query a,query b)
{
    return a.r==b.r?a.l<b.l:a.r<b.r;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        scanf("%d%d",&Q[i].l,&Q[i].r);
        Q[i].id=i;
    }
    seg.build(1,1,n);
    sort(Q+1,Q+1+q,cmp);
    for(int i=1,j=1;i<=n;i++)
    {
        if (pos[a[i]]) seg.update(1,pos[a[i]],INF);
        seg.update(1,i,pos[a[i]]);
        for(;Q[j].r==i&&j<=q;j++)
        {
            PII tmp=seg.getmin(1,Q[j].l,Q[j].r);
            if (tmp.first<Q[j].l) ans[Q[j].id]=a[tmp.second];
        }
        pos[a[i]]=i;
    }
    for(int i=1;i<=q;i++)
        printf("%d\n",ans[i]);
    return 0;

}