FHQ平衡树加线段树玄关求调,马蜂较好注释少许
查看原帖
FHQ平衡树加线段树玄关求调,马蜂较好注释少许
1470997
xpigeon楼主2024/12/25 20:43

求各位大佬帮忙看看哪里有问题,蒟蒻从下午开始写调到晚上还是没调出来,目前知道的是查询排名为k的值和前驱后继问题较大,但左调右调调不出来,可能是前面模板写的不太对,因为线段树和treap也是两周内刚学的写的有点蒙,如果有大佬愿意调我的垃圾代码我真的会非非非非非常感谢

#include<bits/stdc++.h>
using namespace std;
const int M=5e4; 
int n,m,a[M];
//题意 
struct treap_node{
	int l,r,cnt,val,rnd,size;
}tb[M*4];//平衡树单点信息 

int tot; 

struct FHQ_treap{//打包一个平衡树 
	int root;
	inline int newnode(int v) {//新建节点 
    	tb[++tot].val = v;
    	tb[tot].rnd = rand();
    	tb[tot].size = 1;
    	return tot;
	}
	inline void pushup(int p){
		tb[p].size=tb[tb[p].l].size+tb[tb[p].r].size+1; 
		return ;
	}
	//               编号  按v分裂  左右子树编号          
	inline void split(int p,int v,int &x,int &y){
		if(!p){x=y=0;return;}//空树
		if(tb[p].val<=v){//右子树要被分裂 
			x=p;
			split(tb[p].r,v,tb[p].r,y); 
		}
		else{
			y=p;
			split(tb[p].l,v,x,tb[p].l);
		}
		pushup(p);
	}
	//             两个根节点 
	inline int merge(int x,int y){//合并两颗treap 返回值是根节点编号
		if(!x||!y){
			return x+y;
		}
		if(tb[x].rnd<tb[y].rnd){//按堆的性质小的放上面当根 
			merge(tb[x].r,y);
			pushup(x);
			return x;
		}else{
			merge(x,tb[y].l);
			pushup(y);
			return y;
		}
	}
	inline void insert(int v){
		int x,y;
		split(root,v,x,y);
		int z=newnode(v);
		root=merge(merge(x,z),y);
		return ;
	}
	inline void del(int v){
		int x,y,z;
		//剖出"v" 
		split(root,v,x,z);
		split(x,v-1,x,y);
		y=merge(tb[y].l,tb[y].r);
		root=merge(merge(x,y),z); 
		return ;
	}
	inline int _rank(int v){//就是小于v的节点数+1
		int x,y,ans;
		split(root,v-1,x,y);
		if(tb[x].size)
			ans=tb[x].size+1;
		root=merge(x,y);
		return ans;
	}
	inline int topk(int p,int k){
		int lsz=tb[tb[p].l].size;
		if(lsz+1==k){//说明topk是当前节点 
			return tb[p].val; 
		}else if(lsz+1<k){//在右子树 
			return topk(tb[p].r,k-lsz-1); 
		}else if(lsz+1>k){
			return topk(tb[p].l,k);
		}
	}
	inline int get_pre(int v){
		int x,y,ans;
		split(root,v-1,x,y);
		//x都小于v 
		if(tb[x].size)
			ans=topk(x,tb[x].size);
		else
			ans=INT_MIN;
		root=merge(x,y);
		return ans;
	}
	inline int get_suc(int v){
		int x,y,ans;
		split(root,v,x,y);
		if(tb[y].size)
			ans=topk(y,1);
		else
			ans=INT_MAX;
		root=merge(x,y);
		return ans;
	}
};

#define lson (i<<1)
#define rson (i<<1|1)
//这里有一些宏定义
struct seg_node{
	int l,r;
	FHQ_treap tx;
}ts[M*4];

inline void build_tree(int i,int l,int r){
	ts[i].l=l;
	ts[i].r=r;
	for(int j=l;j<=r;j++){
		ts[i].tx.insert(a[j]);
	}
	if(l==r){
		return ;
	}
	int mid=(l+r)/2;
	build_tree(lson,l,mid);
	build_tree(rson,mid+1,r);
}
inline void change(int i,int p,int k){
	ts[i].tx.del(a[p]);
	ts[i].tx.insert(k);
	if(ts[i].l==ts[i].r){
		return;
	}
	int mid=(ts[i].l+ts[i].r)/2;
	if(p<=mid){//左儿子还得改 
		change(lson,p,k);
	}
	else if(p>mid){//右儿子还得改 
		change(rson,p,k);
	}
	return ;
}
inline int query_rank(int i,int l,int r,int k){//排名 
	if(ts[i].l>r || ts[i].r<l){
		return 0;
	}
	if(l<=ts[i].l&& ts[i].r<=r){
		return ts[i].tx._rank(k)-1; 
	}
	//分别在左右孩子里找 
	return query_rank(lson,l,r,k)+query_rank(rson,l,r,k);
}
inline int query_topk(int l,int r,int k){//这里不知道什么东西错了 
	int x=0,y=1e8,ans=0;//二分答案
	while(x<=y){
		int mid=(x+y)/2;
		//cout<<query_rank(1,l,r,mid)<<" ";一直是2??? 
		if(query_rank(1,l,r,mid)+1<=k){
			ans=mid;
			x=mid+1;
		}else{
			y=mid-1;
		}
	} 
	return ans;
} 
inline int query_pre(int i,int l,int r,int v){
	if(ts[i].l>r || ts[i].r<l){
		return INT_MIN;
	}
	if(l<=ts[i].l && ts[i].r<=r){
		return ts[i].tx.get_pre(v);
	}
	return max(query_pre(lson,l,r,v),query_pre(rson,l,r,v));
}
inline int query_suc(int i,int l,int r,int v){
	if(ts[i].l>r || ts[i].r<l){
		return INT_MAX;
	}
	if(l<=ts[i].l && r>=ts[i].r){
		return ts[i].tx.get_suc(v);
	}
	return min(query_suc(lson,l,r,v),query_suc(rson,l,r,v));
}
int main(){
	srand('线段树和平衡树放过我吧');
//	ios::sync_with_stdio(0);
//	cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	build_tree(1,1,n);
	for(int i=1;i<=m;i++){
		int opt,l,r,k,pos;
		cin>>opt;
		if(opt==1){
			cin>>l>>r>>k;
			cout<<query_rank(1,l,r,k)+1<<'\n';
		}
		if(opt==2){
			cin>>l>>r>>k;
			cout<<query_topk(l,r,k)<<'\n';
		}
		if(opt==3){
			cin>>pos>>k;
			change(1,pos,k);
			a[pos]=k;
		}
		if(opt==4){
			cin>>l>>r>>k;
			cout<<query_pre(1,l,r,k)<<'\n';
		}
		if(opt==5){
			cin>>l>>r>>k;
			cout<<query_suc(1,l,r,k)<<'\n';
		}
	}
	return 0;
}
2024/12/25 20:43
加载中...