FJOI 2015 火星商店问题 题解

因为要求最大异或,可以想到 Trie 树,这里又有一个时间限制,二重限制应该是需要树套树的,这里对每一个商店都建一颗 Trie 树,而总体用一颗线段树维护。但是这里的区间不是前缀的,直接用树套树需要用可持久化,但是不想写怎么办,可以对每一个 Trie 树中的每一个点都打一个时间标记,表示这个点的最晚时间,在查询的时候若最晚时间都小于查询的最早时间,那就不能选字典树上的这个点。

时间复杂度是 \(O(m\log^2 n)\)

注意动态开点 Trie 树总大小要开到 \(10^7\) 以上,不然会 RE。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+6,inf=1e9;
int ch[N*300][2],tag[N*300],rt[N*300],tot;
int n,m,a[N];
void tomax(int &x,int y){
	if(x<y)x=y;
}
void insert(int p,int w,int t){
	for(int i=19;i>=0;i--){
		bool tmp=(w&1<<i);
		if(!ch[p][tmp])ch[p][tmp]=++tot;
		p=ch[p][tmp];
		tomax(tag[p],t);
	}
}
int que(int p,int w,int t){
	int res=0;
	for(int i=19;i>=0;i--){
		bool op=(w&1<<i);
		if(ch[p][!op] && tag[ch[p][!op]]>=t){
			res+=1<<i; 
			p=ch[p][!op];
		}
		else if(ch[p][op] && tag[ch[p][op]]>=t)
			p=ch[p][op];
		else return -1;
	} 
	return res;
}//询问时间>=t的最大值 
struct SEG{
	#define ls p<<1
	#define rs p<<1|1 
	int c[N<<2];
	void build(int p,int l,int r){
		c[p]=++tot;
		for(int i=l;i<=r;i++)
			insert(c[p],a[i],inf);
		if(l==r)return ;
		int mid=l+r>>1;
		build(ls,l,mid),build(rs,mid+1,r);
	}
	void change(int p,int l,int r,int x,int w,int t){
	 	insert(c[p],w,t);
		if(l==r)return ; 
		int mid=l+r>>1;
		if(x<=mid)change(ls,l,mid,x,w,t);
		else change(rs,mid+1,r,x,w,t);
	}
	int query(int p,int l,int r,int L,int R,int w,int t){
		if(L<=l&&r<=R)return que(c[p],w,t);
		int mid=l+r>>1;
		if(L<=mid && R>mid) return max(query(ls,l,mid,L,R,w,t),query(rs,mid+1,r,L,R,w,t));
		if(L<=mid)return query(ls,l,mid,L,R,w,t);
		return query(rs,mid+1,r,L,R,w,t); 
	}
}seg;
signed main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",a+i);
	seg.build(1,1,n);
	int d=1;
	for(int i=1,op,s,v,l,r,x,D;i<=m;i++){
		scanf("%d",&op);
		if(op==0){d++;
			scanf("%d%d",&s,&v);
			seg.change(1,1,n,s,v,d); 
		}
		else {
			scanf("%d%d%d%d",&l,&r,&x,&D);
			cout<<seg.query(1,1,n,l,r,x,d-D+1)<<endl; 
		}
	}
	return 0;
}

posted @ 2025-07-15 21:04  hnczy  阅读(10)  评论(0)    收藏  举报