链接:https://www.luogu.org/problemnew/show/P4585
做法:首先观察到每个人能买的商品是一段区间,考虑将这个区间拆成log段存在线段树节点上(开vector),这样就可以考虑对线段树每个节点所代表的商品区间建一棵可持久化trie,然后更新它这个节点上的所有询问,这样做其实算是一种整体二分,复杂度n*log^2
(做这题第一发wa了,调了1个小时发现空间开小了mmp,原来trie里插入一个x位的数是要开x+1个点的...平时这么开没关系是因为trie里很多节点是共用的,而可持久化trie是严格开满的就gg了......)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+100,lim=1<<17;
template<class T>
void rd(T &x)
{
char c=getchar();x=0;bool f=0;
while(!isdigit(c))f|=(c=='-'),c=getchar();
while(isdigit(c))x=x*10+c-48,c=getchar();
if(f)x=-x;
}
void Mx(int &x,int y)
{x=max(x,y);}
struct Trie{
int nxt[20*N][2],sz[20*N],tot,edit[N];
void clear(){tot=0,nxt[0][0]=nxt[0][1]=0,sz[0]=0,edit[0]=0;}
int ins(int bf,int x,int mo)
{
int nw=++tot;
sz[nw]=sz[bf]+1;
if(!mo)return nw;
nxt[nw][0]=nxt[bf][0],nxt[nw][1]=nxt[bf][1];
if(x&mo)nxt[nw][1]=ins(nxt[bf][1],x,mo>>1);
else nxt[nw][0]=ins(nxt[bf][0],x,mo>>1);
return nw;
}
int qry(int fr,int to,int x,int mo)
{
if(!mo)return 0;
int op=(x&mo)?0:1;
if(sz[nxt[to][op]]-sz[nxt[fr][op]]>=1)return mo+qry(nxt[fr][op],nxt[to][op],x,mo>>1);
else return qry(nxt[fr][op^1],nxt[to][op^1],x,mo>>1);
}
int ask(int fr,int to,int x)
{return qry(edit[fr],edit[to],x,lim);}
void insert(int id,int x)
{edit[id]=ins(edit[id],x,lim);}
}trie;
struct pp{
int l,r,L,R,x;
pp(){};
pp(int l,int r,int L,int R,int x):l(l),r(r),L(L),R(R),x(x){};
}qry[N];int qnum=0;
struct th{
int tim,wh,val;
th(){};
th(int tim,int wh,int val):tim(tim),wh(wh),val(val){};
}buy[N],tax1[N],tax2[N];
int n,m,tim=0,ans[N],hav[N],hnum;
vector<int>seg[N<<2];
bool cmp(th x,th y)
{return x.wh<y.wh;}
void seg_ins(int l,int r,int k,int L,int R,int val)
{
if(L>R)return;
if(L<=l&&r<=R)seg[k].push_back(val);
else
{
int mid=(l+r)>>1;
if(L<=mid)seg_ins(l,mid,k<<1,L,R,val);
if(R>mid)seg_ins(mid+1,r,k<<1|1,L,R,val);
}
}
void sol(int l,int r,int L,int R,int k)
{
if(L>R)return;
int nw=0;
trie.clear(),hnum=0;
for(int i=L;i<=R;i++)
{
++nw,hav[++hnum]=buy[i].wh,trie.edit[nw]=trie.edit[nw-1];
trie.insert(nw,buy[i].val);
}
for(int i=0,lps,rps;i<seg[k].size();i++)
{
nw=seg[k][i];
lps=upper_bound(hav+1,hav+hnum+1,qry[nw].l-1)-hav-1;
rps=upper_bound(hav+1,hav+hnum+1,qry[nw].r)-hav-1;
Mx(ans[nw],trie.ask(lps,rps,qry[nw].x));
}
if(l==r)return;
int tnum1=0,tnum2=0,mid=(l+r)>>1;
for(int i=L;i<=R;i++)
{
if(buy[i].tim<=mid)tax1[++tnum1]=buy[i];
else tax2[++tnum2]=buy[i];
}
for(int i=1;i<=tnum1+tnum2;i++)
{
if(i<=tnum1)buy[L+i-1]=tax1[i];
else buy[L+i-1]=tax2[i-tnum1];
}
sol(l,mid,L,L+tnum1-1,k<<1);
sol(mid+1,r,L+tnum1,R,k<<1|1);
}
int main()
{
rd(n),rd(m);
trie.clear();
for(int i=1,tmp;i<=n;i++)
rd(tmp),trie.edit[i]=trie.edit[i-1],trie.insert(i,tmp);
int op,x,y,d,l,r;
for(int i=1;i<=m;i++)
{
rd(op);
if(op)
{
rd(l),rd(r),rd(x),rd(d);
qry[++qnum]=pp(l,r,max(1,tim-d+1),tim,x);
ans[qnum]=trie.ask(l-1,r,x);
}
else
{
rd(x),rd(y),++tim;
buy[tim]=th(tim,x,y);
}
}
for(int i=1;i<=qnum;i++)seg_ins(1,tim,1,qry[i].L,qry[i].R,i);
sort(buy+1,buy+tim+1,cmp);
sol(1,tim,1,tim,1);
for(int i=1;i<=qnum;i++)
printf("%d\n",ans[i]);
}