解题思路
看到区间异或最大值,我们可以想到可持久化Trie树
而看到动态的加入和删除,我们想到线段树分治
因此把这两个结合起来就行了
这个题和一般的线段树分治不太一样的的是,并不是物品有时间范围,而是查询有时间范围,我们知道最值问题是有可重叠性的,因此可以把每个询问的区间插入到时间线段树中,查询的时候
我们可以先对物品按照商店编号排序,保证建立可持久化Trie树的时候更容易
假设我们在线段树上遍历了某个区间,就把这个区间内的所有物品一起构建一颗可持久化0/1Trie,然后因为没有时间的限制,我们把这个区间内的询问的答案更新就行了
退出的时候为了减少撤销的复杂度,可以直接重构Trie树
复杂度
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Sell
{
int x,v,t;
}A[N],tmp[N];
struct Buy
{
int l,r,tl,tr,x;
}Q[N];
bool cmp(Sell x,Sell y)
{
return x.x<y.x;
}
int rot[N];
int trie[64*N][2];
int val[64*N];
int tot=0;
void Insert(int &x,int y,int w,int len)
{
x=++tot;
trie[x][0]=trie[y][0];
trie[x][1]=trie[y][1];
val[x]=val[y]+1;
if(len==-1) return;
bool c=(w&(1<<len));
Insert(trie[x][c],trie[y][c],w,len-1);
}
int Ask(int l,int r,int w,int len)
{
if(len==-1) return 0;
bool c=(w&(1<<len));
if(val[trie[r][c^1]]-val[trie[l][c^1]]>0) return Ask(trie[l][c^1],trie[r][c^1],w,len-1)+(1<<len);
else return Ask(trie[l][c],trie[r][c],w,len-1);
}
int n,m,Ans[N];
vector<int> Query[N<<2];
int cnt1=0,cnt2=0;
void Add(int k,int l,int r,int L,int R,int x)
{
if(L>R) return;
if(L<=l&&r<=R)
{
Query[k].push_back(x);
return;
}
int mid=(l+r)>>1;
if(L<=mid) Add(k<<1,l,mid,L,R,x);
if(R>mid) Add(k<<1|1,mid+1,r,L,R,x);
}
int s[N];
int top=0;
int Search(int x)
{
int l=1,r=top,res=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(s[mid]<=x)
{
res=mid;
l=mid+1;
}
else r=mid-1;
}
return res;
}
void Calc(int k,int L,int R)
{
top=0;
tot=0;
for(int i=L;i<=R;i++)
{
s[++top]=A[i].x;
Insert(rot[top],rot[top-1],A[i].v,17);
}
for(int i=0;i<Query[k].size();i++)
{
int id=Query[k][i];
int l=Search(Q[id].l-1),r=Search(Q[id].r);
Ans[id]=max(Ans[id],Ask(rot[l],rot[r],Q[id].x,17));
}
}
void solve(int k,int l,int r)
{
int mid=(l+r)>>1;
Calc(k,l,r);
if(l==r) return;
int topl=l,topr=mid+1;
for(int i=l;i<=r;i++)
{
if(A[i].t<=mid) tmp[topl++]=A[i];
else tmp[topr++]=A[i];
}
for(int i=l;i<=r;i++) A[i]=tmp[i];
solve(k<<1,l,mid);
solve(k<<1|1,mid+1,r);
}
int main()
{
n=read();
m=read();
for(int i=1;i<=n;i++)
{
int x=read();
Insert(rot[i],rot[i-1],x,17);
}
for(int i=1;i<=m;i++)
{
int opt=read();
if(opt==0)
{
int x=read(),v=read();
cnt1++;
A[cnt1]=(Sell){x,v,cnt1};
}
else
{
int l=read(),r=read(),x=read(),d=read();
Ans[++cnt2]=Ask(rot[l-1],rot[r],x,17);
Q[cnt2]=(Buy){l,r,max(1,cnt1-d+1),cnt1,x};
}
}
for(int i=1;i<=cnt2;i++) Add(1,1,cnt1,Q[i].tl,Q[i].tr,i);
sort(A+1,A+cnt1+1,cmp);
solve(1,1,cnt1);
for(int i=1;i<=cnt2;i++)
printf("%d\n",Ans[i]);
return 0;
}