zoukankan      html  css  js  c++  java
  • 洛谷P3834 【模板】可持久化线段树 主席树

    网址:https://www.luogu.org/problem/P3834

    题意:

    就是给出$n$个数,$m$个询问,询问区间$l$~$r$的第$k$小。

    题解:

    建立一颗权值线段树,就是线段树节点保存的是该子树下的不同的数字的个数,然后对于区间$[1,k]$,$k in (1,n)$建立线段树,显然区间$[1,r]-[1,l-1]$即为所求区间的数字的个数,然后再在这个区间查询即可。具体见代码。

    AC代码:

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define MAXN 200005
    struct value
    {
        int id;
        int x;
    };
    value v[MAXN];
    int hashing[MAXN];
    bool cmp(const value &a,const value &b)
    {
        return a.x<b.x;
    }
    int cnt=0;
    struct cheiftree
    {
        struct node
        {
            int l,r;//l,r记录节点编号而不是区间长
            int sum;
            node()
            {
                sum=0;
            }
        };
        node tr[MAXN*20];
        int root[MAXN];
        void init()
        {
            cnt=1;//树根计数
            tr[0].l=tr[0].r=tr[0].sum=0;//左右孩子的权值初始化为0
            root[0]=0;//树根初始化为0      
        }
        void update(int l,int r,int &nrt,int num)//l,m表示区间范围
        {
            tr[cnt++]=tr[nrt];//新的树根,nrt代表的单元此时为root[i-1]
            nrt=cnt-1;//将cnt-1赋给root[i]即为将树根标记序号
            ++tr[nrt].sum;//然后传入一个新数,权值即数的个数+1,数量即为root[i-1]+1
            if(l==r)//到达叶节点
                return;
            int m=(l+r)/2;//计算区间中点
            if(num<=m)
                update(l,m,tr[nrt].l,num);//把当前树根的左孩子传入
                //由于update使用引用,故左孩子将会被挂到其父亲节点上
            else
                update(m+1,r,tr[nrt].r,num);
                //右孩子同理
        }
        int query(int rl,int rr,int k,int l,int r)//rl指前i棵树,rr指前j棵树,k指第k大,l和r指范围
        {
            int d=tr[tr[rr].l].sum-tr[tr[rl].l].sum;//首次传入rl与rr是树根root[a-1]与root[b],然后tr[rr].l与tr[rl].l就是两树根的左儿子,d表示这个区间的前半段的最大权值(就是最大第几小)
            if(l==r)
                return l;
            int m=(l+r)/2;
            if(k<=d)
                return query(tr[rl].l,tr[rr].l,k,l,m);//k在其中
            else
                return query(tr[rl].r,tr[rr].r,k-d,m+1,r);//k大于最大权值
        }
    };
    cheiftree ct;
    int main()
    {
        int n,m;
        ios::sync_with_stdio(0);
        cin.tie(0);
        cin>>n>>m;
        //离散化
        for(int i=1;i<=n;++i)
            cin>>v[i].x,v[i].id=i;
        sort(v+1,v+1+n,cmp);
        for(int i=1;i<=n;++i)
            hashing[v[i].id]=i;
        //主席树
        ct.init();
        for(int i=1;i<=n;++i)
        {
            ct.root[i]=ct.root[i-1];
            ct.update(1,n,ct.root[i],hashing[i]);//每次加入一个值时建立一棵新树,把节点新值加入到权值树中
        }
        int a,b,k;
        for(int i=0;i<m;++i)
        {
            cin>>a>>b>>k;
            //v[i].id=b,hash[v[i].id]=c => v[c]=v[hash[v[i].id]]=v[i];
            cout<<v[ct.query(ct.root[a-1],ct.root[b],k,1,n)].x<<endl;//查询区间第k大的hash值,然后逆推出真实值
        }
        return 0;
    }
    
  • 相关阅读:
    halcon学习笔记——(5)HDevelop language(异常处理)
    halcon学习笔记——(7)HALCON标定后的二维测量
    halcon学习笔记——(4)HDevelop language(结构语句)
    halcon学习笔记——(3)HDevelop language(基本语句)
    halcon学习笔记——(2)HDevelop language(基本数据类型)
    VMware虚拟机克隆Linux系统后找不到eth0网卡的问题
    完全分布模式安装Hadoop
    Hadoop小程序数据筛选
    SpringMVC访问静态资源
    Win7下IE9访问QC
  • 原文地址:https://www.cnblogs.com/Aya-Uchida/p/11247303.html
Copyright © 2011-2022 走看看