• 主席树——求区间[l,r]不同数字个数的模板(向左密集 D-query)


    主席树的另一种用途,,(还有一种是求区间第k大,区间<=k的个数)

    事实上:每个版本的主席树维护了每个值最后出现的位置

    这种主席树不是以权值线段树为基础,而是以普通的线段树为下标的

    /*
    无修改,求区间[l,r]有多少个不同的数
    主席树的另外一种姿势:
        不像求区间第k大,区间<=k的数有几个之类的可持久化权值线段树,每个结点维护的是当前版本x的出现次数
        本题的主席树每个结点维护当前版本下位置i的值的出现情况 
    更新:以数组a为基础建立线段树,然后从左往右扫描a
        当扫到ai时,如果ai是第一次出现,那么直接在新的线段树上在i位置 +1
        如果值ai在前面位置p出现过,那么在新的线段树上将 p位置 -1,在i位置 +1 
    询问:[l,r]
        首先明确第r棵线段树的rt[1]是[1,r]区间上的不同的数的个数
        现在要求[l,r]上不同的数的个数,那就要把第r棵线段数[l,r]区间的和求出来
        所以只要询问第r棵线段树区间[l,n]的和即可 
    
    可以发现本题并没有用到类似前缀和的思想,因为只要保存各个版本的主席树即可 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 1000005
    struct Node{int lc,rc,sum;}t[100005*25];
    int n,a[maxn],rt[maxn],size,q,pre[maxn],last[maxn]; 
    int build(int l,int r){
        int now=++size;
        t[now].lc=t[now].rc=t[now].sum=0;
        if(l==r)return now;
        int mid=l+r>>1;
        t[now].lc=build(l,mid);
        t[now].rc=build(mid+1,r);
        return now; 
    }
    int update(int last,int pos,int val,int l,int r){//位置pos+val 
        int now=++size;
        t[now]=t[last];t[now].sum+=val;
        if(l==r)return now;
        int mid=l+r>>1;
        if(pos<=mid)t[now].lc=update(t[last].lc,pos,val,l,mid);
        else t[now].rc=update(t[last].rc,pos,val,mid+1,r);
        return now;
    }
    int query(int rt,int L,int R,int l,int r){//查询[L,R]的区间和 
        if(L<=l && R>=r) return t[rt].sum;
        int mid=l+r>>1,res=0;
        if(L<=mid)res+=query(t[rt].lc,L,R,l,mid);
        if(R>mid)res+=query(t[rt].rc,L,R,mid+1,r);
        return res;
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]) ;
            pre[i]=last[a[i]];//上一次出现位置 
            last[a[i]]=i;
        }
        rt[0]=build(1,n);
        for(int i=1;i<=n;i++){
            if(pre[i]==0)rt[i]=update(rt[i-1],i,1,1,n);//这个位置+1
            else{
                int tmp=update(rt[i-1],pre[i],-1,1,n);
                rt[i]=update(tmp,i,1,1,n);
            }
        }
        cin>>q;
        while(q--){
            int l,r;
            scanf("%d%d",&l,&r);
            //cout<<t[rt[r]].sum<<'
    ';
            cout<<query(rt[r],l,n,1,n)<<'
    ';
        }
    }
     
  • 相关阅读:
    leetcode------Clone Graph
    leetcode------Anagrams
    leetcode------Simplify Path
    leetcode------Number of Islands
    leetcode------3Sum Closest
    leetcode------4Sum
    leetcode------3Sum
    leetcode------Binary Tree Right Side View
    leetcode------Word Break
    leetcode------House Robber
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10750164.html
Copyright © 2020-2023  润新知