1. 程式人生 > >[BZOJ 3166]Alo 可持久化01Trie

[BZOJ 3166]Alo 可持久化01Trie

解決 高位到低位 max ins pre 操作 stream 我們 ons

這道題入門了 可持久化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;
}

  

[BZOJ 3166]Alo 可持久化01Trie