标签:ch 持久 int 个数 线段 segtree -- 数据结构
可持久化线段树
权值线段树
- 普通的线段树的节点通常储存该区间的值,节点范围是一个区间。权值线段树储存的是该值域内的元素个数,节点范围是一个值域。
- 利用前缀和的思想 一个区间\([l,r]\)的权值线段数可以由\([1,r]\)和\([1,l-1]\)相减得来。
- 但是n棵树占用的空间太大,而这n课树由许多重复的节点,所以新开的一个权值线段树可以在前一个树上面仅对权值有变化的节点进行新建。
可持久化线段树(离线查询)
例题: POJ2104
题目大意:给长度为n的序列,给m个询问,每次询问区间[l,r]内第k小的数。
思路:让区间[1,r]的元素个数减去区间[1,l-1]的元素个数就是区间[l,r]元素个数,在线段树上二分找第k个数的位置。num[l,r]就靠主席树来维护了。
graph TD; A1,5 --> 1,3 1,3 --> 1,2 1,3 -->3,3 1,2-->1,1 1,2-->2,2 A1,5 --> 4,5 B1,5 --> 4,5 4,5 --> 4,4 4,5 --> 5,5 B1,5 --> 1,3:1 1,3:1 --> 3,3:1试着用mermaid画图,一言难尽
插入
创建新树,新树复制旧树,在原树上递归找插入数值所在区间,一路更新。
查询
若l==r直接返回(离散化后的值),算出左子树个数,若大于k,则在左子树中继续找。否则在右子树中找。
大板子
#define il segtree[i].ch[0]
#define ir segtree[i].ch[1]
#define jl segtree[j].ch[0]
#define jr segtree[j].ch[1]
int n ,m;
int a[N];
vector<int>b;
struct SegTree{
int num,ch[2]; //ch0左 ch1右子树
}segtree[N*20];
int cnt,rt[N];
//后一树的根,前一树的根,区间l,r,查询值k
void update(int &i,int j,int l,int r,int k){
i=++cnt; //新树的树根编号,也就是当前主席树中点的个数
segtree[i] = segtree[j]; //新树复制旧树
++segtree[i].num; //修改权值
if(l==r) return ;
int mid = l+r>>1;
if(k<=mid) update(il,jl,l,mid,k); //修改做子树
else update(ir,jr,mid+1,r,k); //修改右子树
}
//前,后
int query(int i,int j,int l,int r,int k){
if (l==r) return l;
int s = segtree[jl].num - segtree[il].num;
int mid = l + r >> 1;
if(k<=s) return query(il,jl,l,mid,k);
else return query(ir,jr,mid+1,r,k-s);
}
int main(){
int l,r,k;
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i],b.push_back(a[i]);
sort(b.begin(),b.end());
b.erase(unique(b.begin(),b.end()),b.end());//我这个离散化下标从0开始了,下面还要加减一下
int tot = b.size(); //离散化后元素个数
for(int i=1;i<=n;i++){
a[i] = lower_bound(b.begin(),b.end(),a[i])-b.begin()+1;
}
for(int i=1;i<=n;i++){
update(rt[i],rt[i-1],1,tot,a[i]);
}
while(m--){
cin>>l>>r>>k;
cout<<b[query(rt[l-1],rt[r],1,tot,k)-1]<<endl;
}
return 0;
}
标签:ch,持久,int,个数,线段,segtree,--,数据结构 来源: https://www.cnblogs.com/muscletear/p/15306446.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。