可持久化线段树&trie

本文详细介绍了两种高效的数据结构——可持久化线段树和可持久化trie。可持久化线段树在修改和查询时能保存历史状态,适用于动态维护区间信息。而可持久化trie则用于处理字符串或数字的查询,特别是异或等操作。通过实例展示了它们如何处理插入、查询和最大值计算等问题,揭示了其在信息技术领域的实用价值。
摘要由CSDN通过智能技术生成

1.可持久化线段树

思想:每次修改时候新开一条链记录修改的值,并且将这条链与原图相连

struct segment_tree{
	int id[25000010],ls[25000100],rs[25000010],w[25000010],s[1000010],sz;
	int build(int l,int r){//动态开点,记录一个点左右儿子
		id[0]=1;
		int root=++sz;
		if(l==r){
			w[root]=s[l];
			return root;
		} 
		int mid=(l+r)>>1;
		ls[root]=build(l,mid);
		rs[root]=build(mid+1,r);
		return root;
	}
	int insert(int l,int r,int lasid,int h,int wz,int x){
		int root=++sz;//新加的点
		if(l==r){
			w[root]=x;
			return root;
		} 
		int mid=(l+r)>>1;
		if(wz<=mid){//添加的是左节点
			ls[root]=insert(l,mid,ls[lasid],h,wz,x);//左节点新加
			rs[root]=rs[lasid];//右节点与上次的右节点连接
		}else{//同上
			ls[root]=ls[lasid];
			rs[root]=insert(mid+1,r,rs[lasid],h,wz,x);
		}
		return id[h]=root;
	}
	int query(int l,int r,int lasid,int wz,int h){//查找第k次数
		int root=++sz;
		if(l==r){
			w[root]=w[lasid];
			return w[lasid];
		} 
		ls[root]=ls[lasid];
		rs[root]=rs[lasid];
		int mid=(l+r)>>1;
		if(wz<=mid){
			return query(l,mid,ls[lasid],wz,h);
		}else{
			return query(mid+1,r,rs[lasid],wz,h);
		}
	}
};

2.可持久化trie

1) 01trie:将一个数用二进制表示后当作一个字符串插入trie,可以处理异或等操作

例子

每次插入边的权值,然后查询最大值

这里查询运用到了贪心,一个数串从高位到低位依次查询,每次尽量取相反的值(每次去相反可以使最终答案的二进制此位为1)

struct trie{
	int dic[500010][2],num;
	void insert(int x){
		int k=0;
		for(int i=30;i>=0;i--){
			int ty=((x>>i)&1);
			if(!dic[k][ty]) dic[k][ty]=++num;
			k=dic[k][ty];
		}
	}
	int get(int x){
		int k=0,ans=0;
		for(int i=30;i>=0;i--){
			int ty=((x>>i)&1);
			if(dic[k][ty^1]){
				ans|=(1<<i);
				k=dic[k][ty^1];
			}else{
				k=dic[k][ty];
			}
		}
		return ans;	
	}
}; 

2)可持久化trie

例子:插入&查询(l~r)~n的异或最大值

首先将异或前缀和求出来,每次求出x^s[n]^s[k](l<=k<=r)

struct trie{
	int dic[15000001][2],rt[15000010],latest[15000010],num;
	void insert(int x,int id){
		int p1=rt[id]=++num;
		int p2=rt[id-1];
		for(int i=28;i>=0;i--){
			latest[p1]=latest[p2]+1;
			int ty=(x>>i)&1;
			dic[p1][!ty]=dic[p2][!ty];
			if(!dic[p1][ty]) dic[p1][ty]=++num;
			p1=dic[p1][ty];
			p2=dic[p2][ty];
		}
		latest[p1]=latest[p2]+1;
	}
	int query(int l,int r,int x){
		int ans=0;
		int p1=rt[r];
		int p2=rt[max(l-1,0)];
		for(int i=28;i>=0;i--){
			int ty=(x>>i)&1;
			if(latest[dic[p1][!ty]]>latest[dic[p2][!ty]]){
				ans+=(1<<i);
				p1=dic[p1][!ty];
				p2=dic[p2][!ty];
			}else{
				p1=dic[p1][ty];
				p2=dic[p2][ty];
			}
		}
		return ans;
	}
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值