题解 P4585 【[FJOI2015]火星商店问题】
在 Trie 上走的过程相当于是每次询问一个值域区间内是否有值,那么可以用整体二分来做这个过程. 先不考虑一开始的那些东西,那么对于分治到的某一个区间需要求出位置在
该做法的时间复杂度是
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e5+500;
int ans1[N],ans2[N],n,m,qn,cn;
struct BIT
{
int a[N];
void update(int x,int w){for(;x<=n;x+=x&-x)a[x]+=w;}
int query(int x){int ans=0;for(;x;x-=x&-x)ans+=a[x];return ans;}
int query(int l,int r){return query(r)-query(l-1);}
}s,sl,sr;
struct WNode{int l,L,w;}w[N],c[N],tmpwl[N],tmpwr[N];
struct QNode{int l,r,L,R,w,id,exi;}q[N],ql[N],qr[N],tmpq[N<<1];
void solve1(int wl,int wr,int l,int r,int L,int R,int dep)
{
if(l>r||L>R)return;
if(wl==wr)return;
int mid=(wl+wr)>>1;int wnl=0,wnr=0,qnl=0,qnr=0;
for(int i=l;i<=r;i++)
if(w[i].w<=mid)
tmpwl[++wnl]=w[i],sl.update(w[i].l,1);
else tmpwr[++wnr]=w[i],sr.update(w[i].l,1);
for(int i=L;i<=R;i++)
if(q[i].w>>dep&1)
{
if(sl.query(q[i].l,q[i].r))ql[++qnl]=q[i],ans1[q[i].id]|=1<<dep;
else qr[++qnr]=q[i];
}
else
{
if(sr.query(q[i].l,q[i].r))qr[++qnr]=q[i],ans1[q[i].id]|=1<<dep;
else ql[++qnl]=q[i];
}
for(int i=l;i<=r;i++)
if(w[i].w<=mid)sl.update(w[i].l,-1);
else sr.update(w[i].l,-1);
for(int i=1;i<=wnl;i++)w[l+i-1]=tmpwl[i];
for(int i=1;i<=wnr;i++)w[l+wnl+i-1]=tmpwr[i];
for(int i=1;i<=qnl;i++)q[L+i-1]=ql[i];
for(int i=1;i<=qnr;i++)q[L+qnl+i-1]=qr[i];
solve1(wl,mid,l,l+wnl-1,L,L+qnl-1,dep-1);
solve1(mid+1,wr,l+wnl,r,L+qnl,R,dep-1);
}
int cmpq(const QNode &a,const QNode &b){return a.L<b.L;}
void calc(const WNode w[],int wn,QNode q[],int qn)
{
int tn=0;
for(int i=1;i<=qn;i++)
{
q[i].exi=0;
tmpq[++tn]=q[i],tmpq[tn].L=q[i].L-1,tmpq[tn].w=-1,tmpq[tn].id=i;
tmpq[++tn]=q[i],tmpq[tn].L=q[i].R,tmpq[tn].w=1,tmpq[tn].id=i;
}
sort(tmpq+1,tmpq+tn+1,cmpq);
int j=1;
for(int i=1;i<=tn;i++)
{
while(j<=wn&&w[j].L<=tmpq[i].L)s.update(w[j].l,1),++j;
q[tmpq[i].id].exi+=tmpq[i].w*s.query(tmpq[i].l,tmpq[i].r);
}
for(int i=1;i<j;i++)s.update(w[i].l,-1);
}
void solve2(int wl,int wr,int l,int r,int L,int R,int dep)
{
if(l>r||L>R)return;
if(wl==wr)return;
int mid=(wl+wr)>>1;int wnl=0,wnr=0,qnl=0,qnr=0;
for(int i=l;i<=r;i++)
if(c[i].w<=mid)tmpwl[++wnl]=c[i];
else tmpwr[++wnr]=c[i];
for(int i=L;i<=R;i++)
if(q[i].w>>dep&1)ql[++qnl]=q[i];
else qr[++qnr]=q[i];
calc(tmpwl,wnl,ql,qnl),calc(tmpwr,wnr,qr,qnr);
int nl=L,nr=R;
for(int i=1;i<=qnl;i++)
if(ql[i].exi)q[nl++]=ql[i],ans2[ql[i].id]|=1<<dep;
else q[nr--]=ql[i];
for(int i=1;i<=qnr;i++)
if(qr[i].exi)q[nr--]=qr[i],ans2[qr[i].id]|=1<<dep;
else q[nl++]=qr[i];
for(int i=1;i<=wnl;i++)c[l+i-1]=tmpwl[i];
for(int i=1;i<=wnr;i++)c[l+wnl+i-1]=tmpwr[i];
solve2(wl,mid,l,l+wnl-1,L,nr,dep-1),solve2(mid+1,wr,l+wnl,r,nl,R,dep-1);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&w[i].w),w[i].l=i;
qn=0,cn=0;int tim=0;
for(int i=1,opt=-1;i<=m;i++)
{
scanf("%d",&opt);
if(opt==0)
{
++tim;
++cn,scanf("%d%d",&c[cn].l,&c[cn].w),c[cn].L=tim;
}
else ++qn,scanf("%d%d%d%d",&q[qn].l,&q[qn].r,&q[qn].w,&q[qn].L),q[qn].R=tim,q[qn].L=tim-q[qn].L+1,q[qn].id=qn;
}
solve1(0,131071,1,n,1,qn,16);
// for(int i=1;i<=qn;i++)cout<<q[i].id<<" ";puts("");
solve2(0,131071,1,cn,1,qn,16);
// for(int i=1;i<=qn;i++)cout<<ans1[i]<<" ";puts("");
// for(int i=1;i<=qn;i++)cout<<ans2[i]<<" ";puts("");
for(int i=1;i<=qn;i++)printf("%d\n",max(ans1[i],ans2[i]));
}