• One Occurrence 线段树求区间只出现过一次的数字


      题意:一个长度为n的序列(记为A[i]),q次查询,每次输出查询区间内任意一个只出现一次的数字,没有则输出0。

      思路:线段树结点存元素的位置和上一个相同元素出现过的位置(没有则为0,记为pos),线段树维护区间结点最小值,结点封装在pair里,第一key值为前一个相同元素出现的位置,先将查询存下来,对于1到n的每一个前缀【1,r】,维护元素的最右边出现的pos值,例如1 1 2 3 2这个区间,他们的pos值分别是inf,1,inf,0,3。对于已经知道了【1,r】,要得到【1,r+1】,若A【r+1】在前面出现过,则将前面元素的pos值改为inf,再记录自己的pos值。

    像1 1 2 3 2 加进来一个3 ,则pos值的变化为inf,1,inf,0,3—> inf,1,inf,inf,4。这个用线段树的单点更新维护,再将询问以右端点排序,从1开始枚举序列的右端点,若此时的右端点和询问的右端点一致,区间查询一次询问的区间,若得到的pos最小值比l小,代表这个数的上一个值出现的位置再区间外边,则这个数就是查询的答案了,若最小值不符合,则代表没有符合题意的数字。

    AC代码:复杂度nlogn

    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    using namespace std;
    const int maxn=5e5+10,inf=0x3f3f3f3f;
    typedef pair<int,int> pa;
    
    int n,q;
    int A[maxn],ans[maxn],pos[maxn];
    pa a[maxn<<2];
    
    struct Q{
        int l,r,id;
    }p[maxn];
    
    void update(int pos,int val,int l,int r,int rt){
        if(l==r){
            a[rt].first=val;
            a[rt].second=pos;
            return;
        }
        int m=l+r>>1;
        if(pos<=m)
            update(pos,val,l,m,rt<<1);
        else
            update(pos,val,m+1,r,rt<<1|1);
        a[rt]=min(a[rt<<1],a[rt<<1|1]);
    }
    
    pa query(int L,int R,int l,int r,int rt){
        if(L<=l&&r<=R){
            return a[rt];
        }
        int m=l+r>>1;
        pa z;z.first=inf;
        if(L<=m)
            z=min(z,query(L,R,l,m,rt<<1));
        if(R>m)
            z=min(z,query(L,R,m+1,r,rt<<1|1));
        return z;
    }
    
    void check(){
        cout<<"*******************
    ";
        cout<<"pre";
        for(int i=1;i<=11;i++){
            cout<<i<<"->"<<a[i].first<<" ";
        }
        cout<<"
    pos";
        for(int i=1;i<=11;i++){
            cout<<i<<"->"<<a[i].second<<" ";
        }
        cout<<"
    *******************
    
    ";
    }
    
    bool cmp(Q a,Q 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]);
        }
        cin>>q;
        for(int i=1;i<=q;i++){
            scanf("%d%d",&p[i].l,&p[i].r);
            p[i].id=i;
        }
        sort(p+1,p+1+q,cmp);
        for(int i=1,j=1;i<=n;i++){
            if(pos[A[i]]) update(pos[A[i]],inf,1,n,1);
            update(i,pos[A[i]],1,n,1);
            //cout<<"i为"<<i<<endl;
            //check();
            for(;p[j].r==i;j++){
                pa now=query(p[j].l,p[j].r,1,n,1);
                if(now.first<p[j].l){
                    //cout<<"caonima"<<now.second<<endl;
                    ans[p[j].id]=A[now.second];
                }
            }
            pos[A[i]]=i;
        }
        for(int i=1;i<=q;i++){
            printf("%d
    ",ans[i]);
        }
        return 0;
    }
    /*
    6
    1 1 2 2 3 3
    1
    1 3
    */
  • 相关阅读:
    前端使用crypto.js进行加密
    浅谈 Angular 项目实战
    YAML快速入门
    Preloading Your ASP.NET Applications
    ETL利器Kettle实战应用解析系列一【Kettle使用介绍】
    HBase
    hdfs知识点《转》
    Flume概念与原理、与Kafka优势对比《转》
    scrapy 快速入门
    比较好的算法网站
  • 原文地址:https://www.cnblogs.com/qq2210446939/p/12146586.html
Copyright © 2020-2023  润新知