Luogu P4585 [FJOI2015]火星商店问题
题目
可持久化01Trie+线段树分治。
首先用Trie算出所有询问对于特殊商品的答案。
然后我们给每一个进货的商品加上一个时间值,每个询问就会有相对应的时间区间。
我们开一棵时间的线段树,把每个询问加到线段树上,每个节点用一个vector储存这个节点的询问。
显然每个询问最多会在\(log\)个节点上。
然后我们把所有进货按商店排序,由线段树自顶向下进行分治,分治的时候还记录一下进货的区间。
每次到线段树的某个节点时,先计算出当前节点的答案(因为所有进货是按商店排序的,所以依旧可以用01Trie算,算之前记得清空),然后把时间小于等于\(mid\)的放到左边,大于\(mid\)的放到右边,向下递归。
#include<bits/stdc++.h>
#define pb push_back
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
using namespace std;
const int N=100007;
int ch[N<<5][2],sum[N<<5],root[N],ans[N],stk[N],d[18],top,n,m,cnt;
vector<int>vec[N];
struct node{int l,r,L,R,x;}q[N];
struct Node{int s,v,t;}a[N],t1[N],t2[N];
int operator<(Node a,Node b){return a.s<b.s;}
int read(){int x=0;char c=getchar();while(!isdigit(c))c=getchar();while(isdigit(c))x=x*10+c-48,c=getchar();return x;}
int max(int a,int b){return a>b? a:b;}
void split(int x)
{
memset(d,0,sizeof d);
for(int i=0;i<=17;++i) d[i]=x>>i&1;
}
void insert(int &p,int pre)
{
sum[p=++cnt]=sum[pre]+1;
for(int i=17,t=p;~i;--i) ch[t][d[i]^1]=ch[pre][d[i]^1],pre=ch[pre][d[i]],sum[t=ch[t][d[i]]=++cnt]=sum[pre]+1;
}
int query(int l,int r)
{
int ans=0,i;
for(i=17;~i;--i)
if(sum[ch[l][d[i]^1]]^sum[ch[r][d[i]^1]]) ans|=1<<i,l=ch[l][d[i]^1],r=ch[r][d[i]^1];
else l=ch[l][d[i]],r=ch[r][d[i]];
return ans;
}
void update(int p,int l,int r,int L,int R,int x)
{
if(L>R||r<L||l>R) return ;
if(L<=l&&r<=R) return (void)(vec[p].pb(x));
update(ls,l,mid,L,R,x);update(rs,mid+1,r,L,R,x);
}
void cal(int p,int L,int R)
{
cnt=0;
int i,l,r,k,top=0;
for(i=L;i<=R;++i) stk[++top]=a[i].s,split(a[i].v),insert(root[top],root[top-1]);
for(i=0;i<vec[p].size();++i)
k=vec[p][i],l=upper_bound(stk+1,stk+top+1,q[k].l-1)-(stk+1),r=upper_bound(stk+1,stk+top+1,q[k].r)-(stk+1),split(q[k].x),ans[k]=max(ans[k],query(root[l],root[r]));
}
void solve(int p,int l,int r,int L,int R)
{
if(L>R) return;
cal(p,L,R);
if(l==r) return;
int p1=0,p2=0,i;
for(i=L;i<=R;++i) if(a[i].t<=mid) t1[++p1]=a[i]; else t2[++p2]=a[i];
for(i=1;i<=p1;++i) a[i+L-1]=t1[i];
for(i=1;i<=p2;++i) a[i+L+p1-1]=t2[i];
solve(ls,l,mid,L,L+p1-1),solve(rs,mid+1,r,L+p1,R);
}
int main()
{
n=read(),m=read();
int i,tot=0,T=0,l,r,x,d;
for(i=1;i<=n;++i) split(read()),insert(root[i],root[i-1]);
while(m--)
if(read()) l=read(),r=read(),x=read(),d=read(),split(x),ans[++tot]=query(root[l-1],root[r]),q[tot]=(node){l,r,max(1,T-d+1),T,x};
else x=read(),d=read(),a[++T]=(Node){x,d,T};
for(i=1;i<=tot;++i) update(1,1,T,q[i].L,q[i].R,i);
sort(a+1,a+T+1),solve(1,1,T,1,T);
for(i=1;i<=tot;++i) printf("%d\n",ans[i]);
}