CF1000F One Occurrence

CF1000F One Occurrence

题目大意

给定一个长度为\(n\)序列,\(m\)个询问,每次询问给定一个区间\([l,r]\),如果这个区间里存在只出现一次的数,输出这个数(如果有多个就输出任意一个),没有就输出0,\(n,m<=5*10^5\)

分析

看到区间里存在只出现一次的数区间去重。那一下子就想到离线。

那,我们如何判断区间内,某个数是否只存在一个呢?我们先定义一个数组pre[i]表示为i上次出现的位置。

我们假设[l,r]区间内有一个数x其在[l,r]只有自己等价于其上次出现位置<l

我们考虑用线段树维护对某个值来说其上次出现的位置,同时因为需要知道这个值是什么,因此还需要维护一下对应的位置的值。[l,r]存在只出现一次的数,等价于区间最小值<l

同时区间去重操作,一定要记得消除上个位置的影响

因此,我们直接按右端点排序。每扫到一个值,将其上次出现的位置赋到当前位置,同时将上次出现位置上的值置为INF

然后来看代码吧!

Ac_code

#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false); cin.tie(0), cout.tie(0)
using namespace std;

const int N = 5e5 + 10,INF = 0x3f3f3f3f;

struct Node
{
    int l,r;
    int mi,val;
}tr[N<<2];

struct Query
{
    int l,r,id;
    bool operator<(const Query& W)const 
    {
        return r<W.r;
    }
}query[N];
int pre[N],a[N];
int ans[N];
int n,m;

void push(Node &u,Node l,Node r)
{
    if(l.mi<r.mi)
    {
        u.mi = l.mi;
        u.val = l.val;
    }
    else 
    {
        u.mi =r.mi;
        u.val = r.val;
    }
}

void pushup(int u)
{
    push(tr[u],tr[u<<1],tr[u<<1|1]);
}

void build(int u,int l,int r)
{
    tr[u] = {l,r,INF};
    if(l==r) return ;
    int mid = l + r >> 1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
}

void modify(int u,int x,int k)
{
    if(tr[u].l==tr[u].r)
    {
        tr[u].mi = k;
        tr[u].val = a[x];
        return ;
    }
    int mid = tr[u].l + tr[u].r >> 1;
    if(x<=mid) modify(u<<1,x,k);
    else modify(u<<1|1,x,k);
    pushup(u);
}

Node get(int u,int l,int r)
{
    if(l<=tr[u].l&&tr[u].r<=r) return tr[u];
    int mid = tr[u].l + tr[u].r >> 1;
    Node res = {INF,INF,INF,INF};
    if(l<=mid) push(res,res,get(u<<1,l,r));
    if(r>mid) push(res,res,get(u<<1|1,l,r));
    return res;
}

int main()
{
    ios;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    cin>>m;
    for(int i=1;i<=m;i++) 
    {
        int l,r;cin>>l>>r;
        query[i] = {l,r,i};
    }
    build(1,1,n);
    sort(query+1,query+m+1);
    int idx = 1;
    for(int i=1;i<=m;i++)
    {
        while(idx<=query[i].r)
        {
            if(pre[a[idx]]) modify(1,pre[a[idx]],INF);
            modify(1,idx,pre[a[idx]]);
            pre[a[idx]] = idx;idx++;
        }
        auto t = get(1,query[i].l,query[i].r);
        if(t.mi<query[i].l) ans[query[i].id] = t.val;
    }
    for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';
    return 0;
}
posted @ 2022-08-31 10:13  艾特玖  阅读(30)  评论(0)    收藏  举报