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

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;

}



猜你喜欢

转载自blog.csdn.net/u013534123/article/details/80948387