码迷,mamicode.com
首页 > 其他好文 > 详细

主席树

时间:2019-11-03 16:23:53      阅读:94      评论:0      收藏:0      [点我收藏+]

标签:tor   在线   可持久化线段树   const   png   操作   展开   tps   log   

主席树是 以前缀和形式基于权值线段树建立的可持久化线段树,可持久化指的是它保存了这棵树的所有历史版本.

最简单的办法是:如果你输入了n个数,那么每输入一个数字a[i],就构造一棵保存了从a[1]到a[i]的权值线段树,由于只增加了logn的节点数,我们增加改变的节点并将没有改变的子树指向该节点,这样需要的空间开销只有n*(4+logn)

我们可以把第j棵树和第(i-1)棵树上的每个点的权值相减,来得到一棵新的权值线段树,而这个新的权值线段树相当于是输入了a[i]到a[j]以后得到的。

 

模板题 K-th Number

后面将第 k小/大 说成kth 

解决什么问题:
给定一段区间,静态求区间kth 

想想方法:

暴力:对于每一个询问,排个序,就行了,时间复杂度O(nmlogn) 

莫队+树状数组:树状数组可以求给定区间kth kthkth,使用二分+树状数组,具体不展开,但是多个区间的话,需要不断地进行树状数组的add/del操作,那么使用莫队来优化区间端点的移动问题,时间复杂度O((n+m)√n logn) 莫队复杂度*树状数组复杂度

莫队+平衡树:把树状数组的部分替换成二叉查找树,用splay的一部分操作,需要用到kth操作,不用翻转标记什么的,时间复杂度O((n+m)√n logn)跟上面的一样

目前想想,也就这三种方法,各有优劣,暴力时间复杂度不行,但是可以在线
后面两种因为莫队的原因必须离线

但是这三种方法时间都太慢,这个题目我们需要一个O(nlogn) 的做法

于是主席树就诞生了

技术图片

 

 

技术图片
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll ;
const int oo=0x7f7f7f7f ;
const int maxn=1e5+7;
const int mod=1e9+7;
int n,m,cnt,root[maxn],a[maxn],x,y,k;
struct node{
    int l,r,sum;
}T[maxn*25];
vector<int> v;
int getid(int x){
    return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void update(int l,int r,int &x,int y,int pos){
    T[++cnt]=T[y],T[cnt].sum++,x=cnt;
    if(l==r) return;
    int mid=(l+r)/2;
    if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos);
    else update(mid+1,r,T[x].r,T[y].r,pos);
}
int query(int l,int r,int x,int y,int k){
    if(l==r) return l;
    int mid=(l+r)/2;
    int sum=T[T[y].l].sum-T[T[x].l].sum;
    if(sum>=k) return query(l,mid,T[x].l,T[y].l,k);
    else return query(mid+1,r,T[x].r,T[y].r,k-sum);
}
int main(void){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.push_back(a[i]);
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
 
    for(int i=1;i<=n;i++) update(1,n,root[i],root[i-1],getid(a[i]));
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&k);
        printf("%d\n",v[query(1,n,root[x-1],root[y],k)-1]);
    }
 
    return 0;
}
View Code

参考博客:

https://blog.csdn.net/Stupid_Turtle/article/details/80445998

https://blog.csdn.net/ModestCoder_/article/details/90107874

主席树

标签:tor   在线   可持久化线段树   const   png   操作   展开   tps   log   

原文地址:https://www.cnblogs.com/young-children/p/11787490.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!