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;
}

浙公网安备 33010602011771号