题解[P4585火星商店问题]
原题链接
题面过长含糊不清差评
震惊!这题竟没有树状数组套可持久化 \(01trie\) 的题解,补一发。
思路极其简单,由于查询相当于是时间与标号两维限制下求与某个数的异或最大值。
那就可以对时间限制用一个树状数组解决,标号在每个时间下用一颗可持久化 \(01trie\) 就没了。
具体询问时要把树状数组对应时间上标号合法的根拎出来,相当于在时间、标号上都用一次差分。
在找 \(01trie\) 上合法标号的根可以在每个时间上开一个 \(multiset\) ,用 \(lowerbound\) 以及 \(upperbound\) 解决。
还有所谓的特殊商品直接无脑再写一个可持久化 \(01trie\) 取最大值即可。
时间复杂度是 \(O((n+m)\times log(n)^2)\) 的。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=3.5e7+10,K=18;
int n,m,x,y,tt,tot,res,ans;
int a[N],rt[N];
struct inq{int opt,l,r,x,d,t;}q[N];
struct trie{int s[2],sz;}t[M];
void update(int &k,int kk,int x,int i){
k=++tot;t[k]=t[kk];t[k].sz++;if(i<0)return;
bool b=x&(1<<i);update(t[k].s[b],t[kk].s[b],x,i-1);
}
struct node{
int i,x;mutable int rt;
node(int _i,int _x=0):i(_i),x(_x){};
bool operator <(const node &x)const{return i<x.i;};
};
int lowbit(int x){return x&(-x);}
int p[N][2];multiset<node>s[N];
#define msit multiset<node>::iterator
#define f0 for(int i=1;i<=p[0][0];i++)
#define f1 for(int i=1;i<=p[0][1];i++)
void pre_update(int pos,int id,int x){
for(int i=pos;i<=tt;i+=lowbit(i))s[i].insert(node(id,x));
}
void update(){
for(int i=1;i<=tt;i++){
int pre=0;
s[i].insert(node(0,0));//不塞一个空的进去在lower_bound时会出问题
for(msit j=s[i].begin();j!=s[i].end();j++)
update(j->rt,pre,j->x,K),pre=j->rt;
}
}
void inquiry_pre(int l,int r,int pos,bool b){
for(int i=pos;i;i-=lowbit(i)){
msit l1=s[i].lower_bound(node(l));
if(l1==s[i].end())continue;l1--;
msit r1=s[i].upper_bound(node(r));r1--;
p[++p[0][b]][b]=r1->rt,p[++p[0][b^1]][b^1]=l1->rt;
}
}
void inquiry(int x,int k){
if(k<0)return;int tmp=0;bool b=x&(1<<k);
f1 tmp+=t[t[p[i][1]].s[b^1]].sz;f0 tmp-=t[t[p[i][0]].s[b^1]].sz;
if(tmp){res+=1<<k;f0 p[i][0]=t[p[i][0]].s[b^1];f1 p[i][1]=t[p[i][1]].s[b^1];inquiry(x,k-1);}
else {f0 p[i][0]=t[p[i][0]].s[b];f1 p[i][1]=t[p[i][1]].s[b];inquiry(x,k-1);}
}
void inquiry(int k1,int k2,int x,int k){
if(k<0)return;bool b=x&(1<<k);
int tmp=t[t[k2].s[b^1]].sz-t[t[k1].s[b^1]].sz;
if(tmp)res+=1<<k,inquiry(t[k1].s[b^1],t[k2].s[b^1],x,k-1);
else inquiry(t[k1].s[b],t[k2].s[b],x,k-1);
}
void inquiry_(int l,int r,int tl,int tr,int x){
p[0][0]=p[0][1]=0;
inquiry_pre(l,r,tr,1);
inquiry_pre(l,r,tl-1,0);
inquiry(x,K);
}
main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&x),update(rt[i],rt[i-1],x,K);
for(int i=1;i<=m;i++){
scanf("%d",&q[i].opt);
if(q[i].opt)scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].x,&q[i].d);
else scanf("%d%d",&q[i].l,&q[i].x),++tt;
q[i].t=tt;
}
for(int i=1;i<=m;i++)if(!q[i].opt)pre_update(q[i].t,q[i].l,q[i].x);update();
for(int i=1;i<=m;i++)if(q[i].opt){
if(q[i].d&&q[i].t)inquiry_(q[i].l,q[i].r,max(q[i].t-q[i].d+1,1),q[i].t,q[i].x);
ans=res,res=0;inquiry(rt[q[i].l-1],rt[q[i].r],q[i].x,K);ans=max(ans,res);
printf("%d\n",ans);res=ans=0;
}
}