NC19958. [FJOI2015]火星商店问题
描述
输入描述
第1行中给出2个正整数n,m,分别表示商店总数和事件总数。
第2行中有n个整数,第i个整数表示商店i的特殊商品标价。
接下来的m行,每行表示1个事件。每天的事件按照先事件0,后事件1的顺序排列。
输出描述
将计算出的每个事件1的val xor x的最大值依次输出。
示例1
输入:
4 6 1 2 3 4 1 1 4 1 0 0 1 4 0 1 3 1 1 1 1 0 1 1 1 1 1 1 1 2 1 2
输出:
5 0 2 5
C++(clang++11) 解法, 执行用时: 389ms, 内存消耗: 41140K, 提交时间: 2020-10-29 08:19:26
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<queue> using namespace std; #define ll long long #define RG #define MAX 100100 #define lson (now<<1) #define rson (now<<1|1) #define pb(x) push_back(x) inline int read() { RG int x=0,t=1;RG 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 Buy{int s,v,t;}q[MAX],tmp1[MAX],tmp2[MAX]; struct Ask{int l,r,tl,tr,x;}p[MAX]; bool cmp(Buy a,Buy b){return a.s<b.s;} int rt[MAX]; namespace Trie//可持久化Trie { struct Trie{int son[2],w;}t[MAX<<5]; int tot,rt[MAX]; void insert(int &x,int ff,int w,int now) { t[x=++tot]=t[ff];t[x].w++; if(now==-1)return; bool c=w&(1<<now); insert(t[x].son[c],t[ff].son[c],w,now-1); } int Query(int l,int r,int w,int now) { if(now==-1)return 0; bool c=w&(1<<now); int tmp=t[t[r].son[c^1]].w-t[t[l].son[c^1]].w; if(tmp)return Query(t[l].son[c^1],t[r].son[c^1],w,now-1)+(1<<now); else return Query(t[l].son[c],t[r].son[c],w,now-1); } } int n,m,ans[MAX]; vector<int> seg[MAX<<2]; int cnt1,cnt2; //对于线段树的每个节点插入对应的询问 //线段树的每个节点代表着一个购买的时间 //然后对于每个线段树上的节点,维护哪些询问出现在了这些时间之中 //所以对于一个节点维护一个vector,将出现在这段时间中的询问放入vector中 void Modify(int now,int l,int r,int L,int R,int x) { if(L>R)return; if(L<=l&&r<=R){seg[now].pb(x);return;} int mid=(l+r)>>1; if(L<=mid)Modify(lson,l,mid,L,R,x); if(R>mid)Modify(rson,mid+1,r,L,R,x); } int S[MAX],top; //对于当前节点计算在区间内的答案 //考虑如何计算贡献,因为保证了当前节点内的所有询问的时间 //所以只需要考虑区间的问题了,因此按照区间维护可持久化Trie即可 int Binary(int x) { int l=1,r=top,ret=0; while(l<=r) { int mid=(l+r)>>1; if(S[mid]<=x)ret=mid,l=mid+1; else r=mid-1; } return ret; } void Calc(int now,int L,int R) { top=Trie::tot=0; for(int i=L;i<=R;++i) { S[++top]=q[i].s; Trie::insert(rt[top],rt[top-1],q[i].v,17); } for(int i=0,len=seg[now].size();i<len;++i) { int k=seg[now][i]; int l=Binary(p[k].l-1),r=Binary(p[k].r); ans[k]=max(ans[k],Trie::Query(rt[l],rt[r],p[k].x,17)); } } void Divide(int now,int l,int r,int L,int R) { if(L>R)return;int mid=(l+r)>>1,t1=0,t2=0; Calc(now,L,R);if(l==r)return; for(int i=L;i<=R;++i) if(q[i].t<=mid)tmp1[++t1]=q[i]; else tmp2[++t2]=q[i]; for(int i=1;i<=t1;++i)q[i+L-1]=tmp1[i]; for(int i=1;i<=t2;++i)q[i+L-1+t1]=tmp2[i]; Divide(lson,l,mid,L,L+t1-1); Divide(rson,mid+1,r,L+t1,R); } int main() { n=read();m=read(); for(int i=1;i<=n;++i)Trie::insert(rt[i],rt[i-1],read(),17); for(int i=1;i<=m;++i) { int opt=read(); if(!opt) { int s=read(),v=read();++cnt1; q[cnt1]=(Buy){s,v,cnt1}; } else { int l=read(),r=read(),x=read(),d=read(); ans[++cnt2]=Trie::Query(rt[l-1],rt[r],x,17); p[cnt2]=(Ask){l,r,max(1,cnt1-d+1),cnt1,x}; } } for(int i=1;i<=cnt2;++i)Modify(1,1,cnt1,p[i].tl,p[i].tr,i); sort(&q[1],&q[cnt1+1],cmp);//按照商店的编号依次插入所有物品 Divide(1,1,cnt1,1,cnt1); for(int i=1;i<=cnt2;++i)printf("%d\n",ans[i]); return 0; }