zoukankan      html  css  js  c++  java
  • LG3834 可持久化线段树1

    题意

    给定(N)个整数构成的序列,将对于指定的闭区间查询其区间内的第(K)小值。
    $n leq 2 imes 10^5 $

    思路

    ([l,r])区间内的数的个数,可以用(sum[r]-sum[l])来计算,这样的话就很容易想到要开n棵权值线段树,但是一看范围,很显然会(mle),于是就有一个叫主席树的东西出现了。
    当新插入一个数的时候,会发现,只有一条路径上的(sum)会发生变化,其实只要复制这一条路径上的结点就好了。
    插入时,如果它对右儿子无影响,那么将它的右儿子指向原先的树,左儿子继续进行插入操作,反之亦然。查找时用到差分进行左右路径的选择,一直走下去就好了。

    #include <bits/stdc++.h>
    using namespace std;
    const int N=200005;
    int n,m,a[N],b[N],s1[N*40],s2[N*40],sum[N*40],T[N],l,r,x,tot,n2;
    int update(int pre,int l,int r,int x){
        int rt=++tot;
        s1[rt]=s1[pre],s2[rt]=s2[pre],sum[rt]=sum[pre]+1;
        if (l>=r) return rt;
        int mid=(l+r)>>1;
        if (x<=mid) s1[rt]=update(s1[pre],l,mid,x);
        else s2[rt]=update(s2[pre],mid+1,r,x);
        return rt;
    }
    int query(int u,int v,int l,int r,int x){
        if (l==r) return l;
        int mid=(l+r)>>1,tt=sum[s1[v]]-sum[s1[u]];
        if (x<=tt) return query(s1[u],s1[v],l,mid,x);
        else return query(s2[u],s2[v],mid+1,r,x-tt);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+n+1);
        n2=unique(b+1,b+n+1)-b-1;
        for (int i=1;i<=n;i++){
            a[i]=lower_bound(b+1,b+n2+1,a[i])-b;
            T[i]=update(T[i-1],1,n2,a[i]);
        }
        for (int i=1;i<=m;i++){
            scanf("%d%d%d",&l,&r,&x);
            printf("%d
    ",b[query(T[l-1],T[r],1,n2,x)]);
        }
    } 
    
  • 相关阅读:
    关于json前后台传值
    [LeetCode] #29 Divide Two Integers
    [LeetCode] #28 Implement strStr()
    [LeetCode] #27 Remove Element
    [LeetCode] #26 Remove Duplicates from Sorted Array
    [LeetCode] #25 Reverse Nodes in k-Group
    [LeetCode] #24 Swap Nodes in Pairs
    [LeetCode] #23 Merge k Sorted Lists
    [LeetCode] #22 Generate Parentheses
    [LeetCode] #21 Merge Two Sorted Lists
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11805225.html
Copyright © 2011-2022 走看看