• 并不对劲的可持久化线段树主席树


    顾名思义,就是对于每次操作,将用新的节点替代本应修改的节点。由于每次单点修改只会改log n个节点,所以动态开点可以做到空间是q log n + n的。

    这是一棵对劲的线段树,要修改这一串红色的点。普通的线段树是直接修改。

    对于可持久化线段树而言,则是新建一些节点,替换掉应该修改的节点。原来的节点不做任何改动。

    记得存根的版本指针。

    这样就可以实现带撤销操作的线段树了!但是这并不是它的主要优势。它的主要优势在于可以实现主席树(人称Mr.Jiang‘s tree)。

    主席树能查询静态区间第k大。再套上树状数组就能维护动态区间第k大。先考虑静态区间第k大。

    将原数列离散化后,开一棵值域可持久化线段树。按从左到右的顺序插入每一个数。这样,第x个版本的线段树就代表数列中从1到x离散化后在一段取值范围内的出现情况。第0个版本就是一个数都没有。

    查询l到r第k大时,就可以用前缀和的思想,用第r个版本的线段树减去第l-1个。这样得到的线段树就是表示某段取值范围中,在数列中在l-r中的数的个数。当左边的个数大于k时就走左边,否则走右边。需要注意的是,当总共的个数都小于k时,就无解了。

    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #define maxn 200010
    using namespace std;
    int read()
    {
        int f=1,x=0;char ch=getchar();
        while(isdigit(ch)==0 && ch!='-')ch=getchar();
        if(ch=='-')f=-1,ch=getchar();
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void write(int x)
    {
        int ff=0;char ch[15];
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        while(x)ch[++ff]=(x%10)+'0',x/=10;
        if(ff==0)putchar('0');
        while(ff)putchar(ch[ff--]);
        putchar('
    ');
    }
    typedef struct node
    {
        int key,lson,rson;
        
    }tree;
    tree x[maxn*30];
    int n,rt[maxn],a[maxn],cnt,ord[maxn],rnk[maxn],t;
    void build(int li,int ri,int node)
    {
        x[node].key=0;
        if(li==ri)
        {
            x[node].lson=x[node].rson=0;
            return;
        }
        int mid=(li+ri)>>1;
        x[node].lson=++cnt;
        build(li,mid,cnt);
        x[node].rson=++cnt;
        build(mid+1,ri,cnt); 
    }
    int add(int li,int ri,int pla,int k,int node)
    {
        if(ri<pla || li>pla)return node;
        if(li==pla&&ri==pla)
        {
            x[++cnt].key=k;
            return cnt;
        }
        int mid=(li+ri)>>1;
        int lnew=add(li,mid,pla,k,x[node].lson);
        int rnew=add(mid+1,ri,pla,k,x[node].rson);
        int tmp=x[lnew].key+x[rnew].key;
        if(tmp!=x[node].key)
        {
            node=++cnt;
            x[node].lson=lnew,x[node].rson=rnew;
            x[node].key=tmp;
        }
        return node;
    }
    bool cmp(int xx,int yy)
    {
        return a[xx]<a[yy];
    }
    int query(int node1,int node2,int li,int ri,int k)  
    {  
        int mid=(li+ri)>>1;  
        if (li==ri)
        { 
           // cout<<"Shing Zhing Gay"<<endl;
            return li;
        }
    //    cout<<node1<<" "<<node2<<" "<<x[node1].key<<" "<<x[node2].key<<endl; 
        if (x[x[node2].lson].key-x[x[node1].lson].key>=k) return query(x[node1].lson,x[node2].lson,li,mid,k);  
        else if (x[node2].key-x[node1].key>=k) return query(x[node1].rson,x[node2].rson,mid+1,ri,k-(x[x[node2].lson].key-x[x[node1].lson].key));  
        else return 0;  
    } 
    void ask()
    {
        int l=read(),r=read(),k=read();
        int tmp=query(rt[l-1],rt[r],1,n,k);
        write(a[ord[tmp]]);
    }
    void work()
    {
        n=read(),t=read();
        for(int i=1;i<=n;i++)
            a[i]=read(),ord[i]=i;
        rt[0]=cnt=1;
        sort(ord+1,ord+n+1,cmp);
        build(1,n,1); 
        for(int i=1;i<=n;i++)
            rnk[ord[i]]=i;
        for(int i=1;i<=n;i++)
        {
            rt[i]=add(1,n,rnk[i],1,rt[i-1]);
        }
        while(t--)
            ask();
    } 
    int main()
    {
        work();
        return 0;
    }
    /*
    5 5
    25957 6405 15770 26287 26465 
    2 2 1
    3 4 1
    4 5 1
    1 2 2
    4 4 1
    */
    并不对劲的Mr.Jiang's Tree

    gdc没有手

  • 相关阅读:
    217。数据中是否有重复元素(哈希表/set简法)
    悟空、悟能、悟净的理解
    Scala中Self Types实战详解之Scala学习笔记-46
    Scala中Infix Type实战详解之Scala学习笔记-45
    Scala中复合类型实战详解之Scala学习笔记-44
    Scala中结构类型实战详解之Scala学习笔记-43
    Scala中路径依赖代码实战详解之Scala学习笔记-42
    Scala中链式调用风格的实现代码实战及其在Spark编程中的广泛运用之Scala学习笔记-41
    Scala中Variance代码实战及其在Spark中的应用源码解析之Scala学习笔记-40
    Scala类型约束代码实战及其在Spark中的应用源码解析之Scala学习笔记-39
  • 原文地址:https://www.cnblogs.com/xzyf/p/8370814.html
Copyright © 2020-2023  润新知