[BZOJ 3166]Alo 可持久化01Trie

这道题入门了 可持久化01Trie

可持久化Trie多数用来解决区间异或k值之类的操作,主要是由高位到低位按位贪心就可以了

其实和主席树是一样的,Trie本身也有前缀相减性,至于空间,动态开点就可以了。

当然我们需要记录每个节点的size

对于这道题,我们可以用线段树处理出每一个数作为次大值的区间,然后去区间的Trie里面查询异或最大值就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#define N 50100
#include<vector>
#include<algorithm>
using namespace std;
int n;
int a[N],pos[N],lisan[N];
vector<int> b;
int findx(int x){
	return lower_bound(b.begin(),b.end(),x)-b.begin()+1;
}
int sum[N*4];
bool cmp(const int &x,const int &y){
	return x>y;
}
struct haha{
	int left,right;
}cun[N];
int query_r(int pos,int l,int r,int rt){
	if(pos<=0) return 0;
	if(sum[rt]==0) return 0;
	if(l==r) return l;
	int mid=(l+r)>>1;
	if(pos<=mid) return query_r(pos,l,mid,rt<<1);
	else{
		int ans=query_r(pos,mid+1,r,rt<<1|1);
		if(ans!=0) return ans;
		return query_r(pos,l,mid,rt<<1);
	}
}
int query_l(int pos,int l,int r,int rt){
	if(pos>=n+1) return n+1;
	if(sum[rt]==0) return n+1;
	if(l==r) return l;
	int mid=(l+r)>>1;
	if(pos>mid) return query_l(pos,mid+1,r,rt<<1|1);
	else{
		int ans=query_l(pos,l,mid,rt<<1);
		if(ans!=n+1) return ans;
		return query_l(pos,mid+1,r,rt<<1|1);
	}
}
void update(int pos,int l,int r,int rt){
	if(l==r){sum[rt]++;return;}
	int mid=(l+r)>>1;
	if(pos<=mid) update(pos,l,mid,rt<<1);
	else update(pos,mid+1,r,rt<<1|1);
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}

struct Trie{
	Trie *ch[2];int size;
	Trie(){ch[0]=ch[1]=NULL;size=0;}
}*root[N];
int bit[33];
void insert(Trie *&rt,Trie *rt_pre,int num){
	Trie *now=rt,*old=rt_pre;
	pos2(i,31,0){
		int d=num&bit[i];if(d) d=1;else d=0;
		if(old==NULL){
			if(now->ch[d]==NULL)  now->ch[d]=new Trie();
			now->ch[d]->size++;
			now=now->ch[d];
		}
		else{
			now->ch[d^1]=old->ch[d^1];
			if(now->ch[d]==NULL)  now->ch[d]=new Trie();
			int add(0);if(old->ch[d]!=NULL) add=old->ch[d]->size;
			now->ch[d]->size=add+1;
			now=now->ch[d];
			old=old->ch[d];
		}
	}
}
int ans;
int query(int l,int r,int num){
	Trie *nowl=root[l-1],*nowr=root[r];
	int res(0);
	pos2(i,31,0){
		int d=num&bit[i];if(d) d=1;else d=0;
		if(nowl==NULL){
			if(nowr->ch[d]==NULL){
				nowr=nowr->ch[d^1];
				if(d^1) res|=bit[i];
				continue;
			}
			if(nowr->ch[d^1]==NULL){
				nowr=nowr->ch[d];
				if(d) res|=bit[i];
				continue;
			}
			nowr=nowr->ch[d^1];
			if(d^1) res|=bit[i];
		}
		else{
			if(nowr->ch[d]==NULL){
				nowr=nowr->ch[d^1];
				if(d^1) res|=bit[i];
				nowl=nowl->ch[d^1];
				continue;
			}
			if(nowr->ch[d^1]==NULL){
				nowr=nowr->ch[d];
				if(d) res|=bit[i];
				nowl=nowl->ch[d];
				continue;
			}
			int add(0);
			if(nowl->ch[d^1]!=NULL) add=nowl->ch[d^1]->size;
			int size=nowr->ch[d^1]->size - add;
			if(size>=1){
				nowr=nowr->ch[d^1];
				nowl=nowl->ch[d^1];
				if(d^1) res|=bit[i];
			}
			else{
				nowr=nowr->ch[d];
				nowl=nowl->ch[d];
				if(d) res|=bit[i];
			}
		}
	}
	return num^res;
}
int main(){
	scanf("%d",&n);
	root[0]=new Trie();
	bit[0]=1;
	pos(i,1,31) bit[i]=bit[i-1]<<1;
	pos(i,1,n){
		scanf("%d",&a[i]);b.push_back(a[i]);
		root[i]=new Trie();
		insert(root[i],root[i-1],a[i]);
	}
	sort(b.begin(),b.end());
	pos(i,1,n){
		pos[findx(a[i])]=i;
	}
	sort(a+1,a+n+1,cmp);
	update(pos[findx(a[1])],1,n,1);
	pos(i,2,n){
		int lisan=findx(a[i]);
		int posi=pos[lisan];
		int j1=query_r(posi-1,1,n,1);
		if(j1!=0) cun[lisan].left=query_r(j1-1,1,n,1)+1;
		int j2=query_l(posi+1,1,n,1);
		if(j2!=n+1) cun[lisan].right=query_l(j2+1,1,n,1)-1;
		update(posi,1,n,1);
	}
	pos(i,2,n){
		int lisan=findx(a[i]),posi=pos[lisan];
		if(cun[lisan].left!=0){
			ans=max(ans,query(cun[lisan].left,posi-1,a[i]));
		}
		if(cun[lisan].right!=0){
			ans=max(ans,query(posi+1,cun[lisan].right,a[i]));
		}
	}
	printf("%d",ans);
	return 0;
}

  

时间: 2024-10-01 19:38:24

[BZOJ 3166]Alo 可持久化01Trie的相关文章

P4098 [HEOI2013]ALO 可持久化01Trie

$ \color{#0066ff}{ 题目描述 }$ Welcome to ALO ( Arithmetic and Logistic Online).这是一个 VR MMORPG, 如名字所见,到处充满了数学的谜题 现在你拥有 n 颗宝石,每颗宝石有一个能量密度,记为 ai,这些宝石的能量 密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设 为 ai, ai+1, -, aj,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值 与其他任意一颗宝石的能量密度按位异或的值,

BZOJ 3166 Alo

处理出每个数最靠近它的左右两个比它大的数. 然后可持久化trie. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 200050 #define inf 1000000007 using namespace std; struct num { int val,id; }p[maxn]; int n,a[maxn]; int seg_l

bzoj 4137 [FJOI2015]火星商店问题——线段树分治+可持久化01trie树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4137 关于可持久化01trie树:https://www.cnblogs.com/LadyLex/p/7281110.html 看了看它的两道例题,就没写. 特殊商品可以直接用可持久化trie做. 其他部分用线段树分治.修改是单点的,询问是区间,原来想的是把询问区间定位后有 mlogn 个,在线段树的每个叶子上贡献一番:结果TLE了,因为若是在叶子处贡献,一个询问就要做 r-l+1 次.

P5283 [十二省联考2019]异或粽子 可持久化01Trie+线段树

$ \color{#0066ff}{ 题目描述 }$ 小粽是一个喜欢吃粽子的好孩子.今天她在家里自己做起了粽子. 小粽面前有 \(n\) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 \(1\) 到 \(n\).第 \(i\) 种馅儿具有一个非负整数的属性值 \(a_i\).每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子.小粽准备用这些馅儿来做出 \(k\) 个粽子. 小粽的做法是:选两个整数数 \(l\), \(r\),满足 \(1 \leqslant l

可持久化0-1Trie树

我跟可持久化数据结构杠上了 \(QwQ\) .三天模拟赛考了两次可持久化数据结构(主席树.可持久化0-1Trie树),woc. 目录: 个人理解 时空复杂度分析 例题及简析 一.个人理解 可持久化0-1Trie树,是一种可以快速查询区间异或信息的高级数据结构. 它的主要思想和主席树相同,即保存每次插入操作的历史版本,来快速查询区间的异或信息. 0-1Trie树和平常写的strTrie树相同,都是维护前缀信息的数据结构.不同点只有一个,就是0-1Trie树是维护一个0-1串.可持久化0-1Trie

BZOJ 3166 HEOI2013 ALO 可持久化trie+st表

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3166(洛谷上也有) 题意概述: 给出一个序列,对于一个区间,其权值为区间中的次大值亦或区间中任意一个数的结果的最大值.求区间权值的最大值. 分析: 考虑每个点作为区间次大的状态,发现对于每个点至多有两个最长区间其为次大值(为了让异或结果最大当然是区间越长越好,选择最多),用二分+静态RMQ算出这两个区间再在可持久化trie上面贪心即可. 论如何现场yy可持久化数据结构23333(基于可

BZOJ 3166 HEOI2013 Alo 可持久化Trie树

题目大意:给定一个不重复的序列a,在a中任选一个区间,求区间内的次大值与区间内的任意一个其它数的最大的异或值 首先我们枚举次大值 对于一个次大值 它可能选择的另一个数的取值范围为(l,r) 其中l为这个数左侧第二个比它大的数 r为这个数右侧第二个比它大的数 在这个区间内的Trie树中贪心寻找最大值即可 这个区间怎么求呢?我们维护一棵平衡树 将数从大到小将下标加进平衡树 每加进一个下标 比它大的数的下标都在平衡树中 求两次后继就是r 求两次前驱就是l 我偷懒写了set-- #include<set

BZOJ 3166: [Heoi2013]Alo

3166: [Heoi2013]Alo Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 923  Solved: 437[Submit][Status][Discuss] Description Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密