F. One Occurrence

Problem - 1000F - Codeforces

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 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]a=[1,1,2,3,2,4], then for query (li=2,ri=6)(li=2,ri=6) the subarray we are interested in is [1,2,3,2,4][1,2,3,2,4], and possible answers are 11, 33 and 44; for query (li=1,ri=2)(li=1,ri=2) the subarray we are interested in is [1,1][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 nn (1≤n≤5⋅1051≤n≤5⋅105).

The second line contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤5⋅1051≤ai≤5⋅105).

The third line contains one integer qq (1≤q≤5⋅1051≤q≤5⋅105).

Then qq lines follow, ii-th line containing two integers lili and riri representing ii-th query (1≤li≤ri≤n1≤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

Copy

6
1 1 2 3 2 4
2
2 6
1 2

output

Copy

4
0

=========================================================================

在右端点确定的情况下,[L,R]数字出现次数为1次,当且仅当这一区间上一次出现的位置在[1,L-1]或者没有出现,即[L,R]每个数字上一次出现位置的最小值。 所以可以建立以R为根的可持久化线段树,由R-1转移过来。转移过来之后,修改r的上一次出现的位置为 pre[a[r]] ,没有的话,按照0来修改。R[i-1]为根的线段树如果已经存在了 上一个a[R]的上一个位置,如 a[R]  .....  a[R] .... a[R]     。查询[L,R]的时候,R固定,再往前面的a[R]都没有意义,因为只有对于a[R]来说,只有最后一个与倒数第二个之间的L才具有查询意义。所以将第二个a[R]之前的位置设置为无穷大即可

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct node
{
    int l,r,minn;
    int ans;
    friend bool operator< (node a, node b)
    {
        return a.minn<b.minn;
    }
};

struct node tree[500010*40];
int mp[500000+10],tot;
int n,a[500000+10],pre[500000+10];

int clone(int root)
{
    tot++;
    tree[tot]=tree[root];
    return tot;
}
void pushup(int root)
{
    if(tree[tree[root].l].minn<tree[tree[root].r].minn)
    {
        tree[root].ans=tree[tree[root].l].ans;
    }
    else
    {
        tree[root].ans=tree[tree[root].r].ans;
    }
    tree[root].minn=min(tree[tree[root].l].minn,tree[tree[root].r].minn);

}
int change(int root,int l,int r,int pos,int val)
{
    root=clone(root);

    if(l==r)
    {
        tree[root].minn=val;
        tree[root].ans=pos;
        tree[root].l=tree[root].r=root;
        return root;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)
        tree[root].l=change(tree[root].l,l,mid,pos,val);
    else
        tree[root].r=change(tree[root].r,mid+1,r,pos,val);

    pushup(root);

    return root;
}

node query(int root,int l,int r,int L,int R)
{
    if(l>=L&&R>=r)
    {
        return tree[root];
    }
    struct node ans;
    ans.minn=1e9;
    int mid=(l+r)>>1;
    if(L<=mid)
        ans=min(ans,query(tree[root].l,l,mid,L,R));
    if(R>mid)
        ans=min(ans,query(tree[root].r,mid+1,r,L,R));
    return ans;
}
int main()
{
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        cin>>a[i];
        if(pre[a[i]]==0)
        {
            mp[i]=change(mp[i-1],1,n,i,0);
            pre[a[i]]=i;
        }
        else
        {
            mp[i]=change(mp[i-1],1,n,pre[a[i]],1e9);
            mp[i]=change(mp[i],1,n,i,pre[a[i]]);
            pre[a[i]]=i;
        }
    }
    int m;
    cin>>m;
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        struct node pos=query(mp[r],1,n,l,r);

        if(pos.minn<l)
        {
            cout<<a[pos.ans]<<'\n';
        }
        else
        {
            cout<<0<<'\n';
        }
    }

    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秦三码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值