首页 > 其他分享 >主席树

主席树

时间:2023-01-17 14:36:12浏览次数:58  
标签:int sum tree tot ys 主席 zs

主席树是可持久化线段树。
当我想知道某个历史状态下的数据,则需要将每一个状态都存下来,可是会MLE。
但是我们可以发现每次修改只会修改\(log_{2} n\)次,也就是增加\(log_{2} n\)个节点。

例题:洛谷P3834
思路:首先离散化,建一棵权值主席树,因为\(r\)历史状态下个数-\((l-1)\)历史状态下个数就是\([l,r]\)中总个数,然后就和权值线段树求第k小一样。
代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m;
struct nod{
	int zhi;
	int id;
}a[200010];
int b[200010];
struct node{
	int l,r;
	int zs,ys;
	int sum;
}tree[10000010];
int tot=0;
int tou[200010];
bool cmp(nod x,nod y){
	return x.zhi<y.zhi;
}
void build(int i,int l,int r){
	tree[i].l=l;
	tree[i].r=r;
	tree[i].sum=0;
	if(l==r){
		return ;
	}
	int mid=(l+r)/2;
	tree[i].zs=++tot;
	build(tot,l,mid);
	tree[i].ys=++tot;
	build(tot,mid+1,r);
	return ; 
}
void buil(int i,int j,int k){
	tree[i]=tree[j];
	tree[i].sum++;
	if(tree[i].l==tree[i].r){
		return ;
	}
	if(tree[tree[i].zs].r>=k){
		tree[i].zs=++tot;
		buil(tot,tree[j].zs,k);
	}
	else{
		tree[i].ys=++tot;
		buil(tot,tree[j].ys,k);
	}
}
int search(int i,int j,int k){
	if(tree[i].l==tree[i].r){
		return tree[i].l;
	}
	if(tree[tree[i].zs].sum-tree[tree[j].zs].sum>=k){
		return search(tree[i].zs,tree[j].zs,k);
	}
	else{
		return search(tree[i].ys,tree[j].ys,k-tree[tree[i].zs].sum+tree[tree[j].zs].sum);
	}
}
int main(){
	cin>>n>>m;
	tot=1;
	tou[0]=1;
	build(1,1,n);
	for(int i=1;i<=n;i++){
		cin>>a[i].zhi;
		a[i].id=i;
	}
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		b[a[i].id]=i;
	}
	for(int i=1;i<=n;i++){
		tou[i]=++tot;
		buil(tot,tou[i-1],b[i]);
	}
	while(m--){
		int l,r,k;
		cin>>l>>r>>k;
		cout<<a[search(tou[r],tou[l-1],k)].zhi<<endl;
	}
	return 0;
}

标签:int,sum,tree,tot,ys,主席,zs
From: https://www.cnblogs.com/z-2-we/p/17057723.html

相关文章