zoukankan      html  css  js  c++  java
  • CodeForces 1000F One Occurrence

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

    The second line contains $n$ integers $a_1,a_2,…,a_n$ ($1≤a_i≤5⋅10^5$,$1≤a_i≤5⋅10^5$).

    The third line contains one integer $q$ ($1≤q≤5⋅10^5$,$1≤q≤5⋅10^5$).

    Then $q$ lines follow, $i$-th line containing two integers $l_i$ and $r_i$ representing $i$-th query ($1≤l_i≤r_i≤n$,$1≤l_i≤r_i≤n$).

    Output

    Answer the queries as follows:

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

    Example

    Input

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

    Output

    4
    0

    感想

      再也不敢熬夜了,通过熬夜换回了半夜两三个小时,后面几天我要用几十个小时去偿还,利息太高了……一道可以算做过的题,把我卡了那么多天……

    解题思路

      先扔一个链接(HH的项链)//看不懂当年自己的博客什么鬼……这次借着做这题的机会,把当年的博客改得更好懂一点

      同样的思路,把询问离线,按左端点升序排序。搞一个nxt数组,nxt[i]记录下一个和a[i]相同的数字的位置,没有就赋值为inf(无穷大)。搞一棵线段树(树状数组啥的也行,只要能快速单点更新、查询区间最大值就好),记录区间内(nxt[i]最大)的i,代码里变量名是mxi,开始建树时不急着在树上存值,先把mxi全部赋值成0。

      然后,所有第一次出现的数字a[i]在线段树下标i的位置留下痕迹(用自己的nxt[i]去更新线段树,让线段树存下区间内所有留下痕迹的i中nxt[i]最大的i)。

      每次查询之前,先把询问的左端点以左的那些第一次出现的数字处理一下。如果他们的nxt[i]不是inf,就把他们的nxt[i]拿去在线段树上留下痕迹,然后清空他们自己留下的痕迹,查询时que函数会返回一个区间内nxt[i]最大的那个i,代码里变量名为temp,如果nxt[temp]都没超过询问区间的右端点,那么区间里没有只出现一次的数了,答案为0,否则答案就可以是a[temp],下一个相同的出现在区间外(inf也算区间外)。

      最后,把答案按照输入顺序排个序,输出,没了。

      和HH的项链那系列莫队板子题一样,莫队也可以(这题莫队好像要卡常?),主席树也能在线处理询问(我还不会)

    源代码

    #include<stdio.h>
    #include<algorithm>
    
    const int inf=0x7fffffff;
    
    int n,m;
    int a[500010]={0},mx=-1,nxt[500010]={0};
    int p[500010]={0};//类似一个桶,装第i号颜色第一次出现的位置
    
    struct Segtree{
        int l,r;
        int mxi;//区间最大的nxt[i]对应的下标i
    }t[2000010];
    inline int lson(int x){return x<<1;}
    inline int rson(int x){return x<<1|1;}
    void maketree(int x,int l,int r)
    {
        if(l==r)
        {
            t[x]={l,r,0};
            return;
        }
        t[x].l=l;
        t[x].r=r;
        t[x].mxi=0;
        int mid=(l+r)>>1;
        maketree(lson(x),l,mid);
        maketree(rson(x),mid+1,r);
    }
    void update(int x,int pos)
    {
        if(pos>t[x].r||pos<t[x].l) return;
        if(t[x].l==t[x].r)
        {
            t[x].mxi=pos;
            return;
        }
        update(lson(x),pos);
        update(rson(x),pos);
        if(nxt[t[lson(x)].mxi]>nxt[t[rson(x)].mxi])
            t[x].mxi=t[lson(x)].mxi;
        else
            t[x].mxi=t[rson(x)].mxi;
    }
    int que(int x,int l,int r)
    {
        if(l>t[x].r||r<t[x].l) return 0;
        if(l<=t[x].l&&t[x].r<=r)
            return t[x].mxi;
        int templ=que(lson(x),l,r),tempr=que(rson(x),l,r);
        if(nxt[templ]>nxt[tempr]) return templ;
        else return tempr;
    }
    
    struct Ask{
        int l,r,id,ans;
    }ask[500010];
    bool cmp1(const Ask & a,const Ask & b)
    {
        return a.l==b.l?a.r<b.r:a.l<b.l;
    }
    bool cmp2(const Ask & a,const Ask & b)
    {
        return a.id<b.id;
    }
    
    int main()
    {
        //freopen("test.in","r",stdin);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",a+i),mx=std::max(a[i],mx);
        for(int i=n;i>0;i--)//预处理出nxt和p
        {
            if(p[a[i]]) nxt[i]=p[a[i]];
            else nxt[i]=inf;
            p[a[i]]=i;
        }
        maketree(1,1,n);
        for(int i=1;i<=mx;i++)
        {
            if(p[i]) update(1,p[i]);//线段树单点更新
        }
        
        scanf("%d",&m);
        for(int i=1,l,r;i<=m;i++)
        {
            scanf("%d%d",&l,&r);
            ask[i]={l,r,i,0};
        }
        std::sort(ask+1,ask+1+m,cmp1);
    
        for(int i=1,ll=0;i<=m;i++)
        {
            while(ll<ask[i].l)
            {
                if(nxt[ll]!=0x7fffffff)
                {
                    update(1,nxt[ll]);
                    nxt[ll]=0;
                    update(1,ll);
                }
                ll++;
            }
            int temp=que(1,ask[i].l,ask[i].r);//返回nxt最大的那个的下标
            if(nxt[temp]<=ask[i].r) ask[i].ans=0;
            else ask[i].ans=a[temp];
        }
        
        std::sort(ask+1,ask+1+m,cmp2);
        for(int i=1;i<=m;i++)
            printf("%d
    ",ask[i].ans);
    
        return 0;
    }
  • 相关阅读:
    并发编程-阻塞队列&JUC常用工具
    并发编程-Condition源码分析&基于Condition实现阻塞队列
    并发编程-ReentrantLock锁源码分析&Condition设计
    并发编程-JMM&ReentrantLock锁以及原理
    数据库操作支持函数
    python内置进制转换函数
    三目运算符
    数据库常见操作
    宏使用汇总
    sort: invalid comparator
  • 原文地址:https://www.cnblogs.com/wawcac-blog/p/10484848.html
Copyright © 2011-2022 走看看