数据结构–主席树

可持久化线段树

静态区间第 (k)

给定 (n) 个整数构成的序列,将对于指定的闭区间查询其区间内的第 (k) 小值。

权值线段树

权值线段树就是对一个值域上值的个数进行维护的线段树。

举个栗子,对于1,1,2,3,3,3,4,4。

数据结构--主席树

在权值线段树上如何求第k小的值?

显然如果左子树的值大于k的话,那么答案就在左子树上,不然就在右子树上,而且是右子树第(k-左子树值)小。

主席树

我们对每个节点,都新建一颗权值线段树,不过我们保留一些不变的节点,只新建改变的了的节点。

对于询问[L,R],每个root[i]节点所表示的值域都是[1,n],

(t[t[R].l].sum-t[t[L-1].l].sum)表示的就是区间[L,R]内值域属于([1,{n over 2}])数的个数。

如果这个数大于k,那么表示答案落在值域([1,{n over 2}]),不然就表示答案落在值域([{n over 2},n])

下图表示的是先插入一个2,再插入一个3之后的主席树。

数据结构--主席树

code

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
const int inf = 0x3f3f3f3f;
const int maxn = 201110;
const int M = 1e9+7;
int n,m;

int read()
{
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return x;
}

int a[maxn];
vector<int> v;

struct node
{
    int l,r,sum;
}t[maxn*40];

int cnt,root[maxn];

int getid(int x)        //离散化
{
    return lower_bound(v.begin(),v.end(),x)-v.begin() + 1;
}

void insert(int l,int r,int pre,int &now,int p)         //当前插入的区间,pre表示要复制的点,now表示要创建的新节点
{
    t[++cnt] = t[pre];
    now = cnt;
    t[now].sum++;
    int mid = (l+r)/2;
    if(l == r) return;
    if(p <= mid) insert(l,mid,t[pre].l,t[now].l,p);
    else insert(mid+1,r,t[pre].r,t[now].r,p);
}

int query(int l,int r,int L,int R,int k)
{
    if(l == r) return l;
    int mid = (l+r)/2;
    int tmp = t[t[R].l].sum - t[t[L].l].sum;
    if(k <= tmp) return query(l,mid,t[L].l,t[R].l,k);
    else return query(mid+1,r,t[L].r,t[R].r,k-tmp);
}

signed main()
{
#ifdef ONLINE_JUDGE
#else
    freopen("data.in", "r", stdin);
#endif
    n = read(), m = read();
    for(int i = 1; i <= n; i++) 
    {
        v.push_back(a[i] = read());
    }
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    int sz = v.size();
    for(int i = 1; i <= n; i++) 
    {
        insert(1,sz,root[i-1],root[i],getid(a[i]));
    }
    int l,r,k;
    while(m--)
    {
        l = read(), r = read(), k = read();
        printf("%dn",v[query(1,sz,root[l-1],root[r],k)-1]);
    }
    return 0;
}

原文链接: https://www.cnblogs.com/hezongdnf/p/12888336.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    数据结构--主席树

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/324809

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月1日 下午2:56
下一篇 2023年3月1日 下午3:00

相关推荐