[BZOJ4137]火星商店问题
Description
火星上的一条商业街里按照商店的编号1,2 ,…,n ,依次排列着n个商店。商店里出售的琳琅满目的商品中,每种商品都用一个非负整数val来标价。每个商店每天都有可能进一些新商品,其标价可能与已有商品相同。
火星人在这条商业街购物时,通常会逛这条商业街某一段路上的所有商店,譬如说商店编号在区间[L,R]中的商店,从中挑选1件自己最喜欢的商品。每个火星人对商品的喜好标准各不相同。通常每个火星人都有一个自己的喜好密码x。对每种标价为val的商品,喜好密码为x的火星人对这种商品的喜好程度与val异或x的值成正比。也就是说,val xor x的值越大,他就越喜欢该商品。每个火星人的购物卡在所有商店中只能购买最近d天内(含当天)进货的商品。另外,每个商店都有一种特殊商品不受进货日期限制,每位火星人在任何时刻都可以选择该特殊商品。每个商店中每种商品都能保证供应,不存在商品缺货的问题。
对于给定的按时间顺序排列的事件,计算每个购物的火星人的在本次购物活动中最喜欢的商品,即输出val xor x的最大值。这里所说的按时间顺序排列的事件是指以下2种事件:
事件0,用三个整数0,s,v,表示编号为s的商店在当日新进一种标价为v 的商品。
事件1,用5个整数1,L,R,x,d,表示一位火星人当日在编号为L到R的商店购买d天内的商品,该火星人的喜好密码为x。
Input
第1行中给出2个正整数n,m,分别表示商店总数和事件总数。
第2行中有n个整数,第i个整数表示商店i的特殊商品标价。
接下来的m行,每行表示1个事件。每天的事件按照先事件0,后事件1的顺序排列。
Output
将计算出的每个事件1的val xor x的最大值依次输出。
Sample Input
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
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
Sample Output
5
0
2
5
0
2
5
HINT
n, m <= 100000
数据中,价格不大于100000
Source
显然呢这道题可以用线段树套可持久化$Trie$来实现,不过不是我们讨论的范围
我们考虑每个修改对询问的影响是一段区间
按时间建立线段树,那么每个询问对应了线段树不超过$logn$个节点,每次修改对应着从该时间点到根节点的路径
所以每个修改对$logn$个节点有贡献,因此我们在回答每个节点的询问前,直接暴力把对该节点有影响的修改插进线段树即可
因为询问被拆成了许多线段树节点,于是要对这些被拆的询问取$max$
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstring> 6 #define M 100010 7 #define ls node<<1 8 #define rs node<<1|1 9 using namespace std; 10 11 int n,m,cnt,cnt1,cnt2; 12 int rt[M],f[M],ans[M]; 13 vector<int>seg[M<<2]; 14 struct CG{int s,v,t;}q[M],tmp1[M],tmp2[M]; 15 struct ASK{int l,r,l1,r1,x;}p[M]; 16 bool cmp(CG a1,CG a2) {return a1.s<a2.s;} 17 18 struct Trie 19 { 20 int cnt; 21 int val[M<<5],ch[M<<5][2]; 22 void insert(int &now,int pre,int w,int o) 23 { 24 25 now=++cnt,val[now]=val[pre]+1; 26 ch[now][0]=ch[pre][0];ch[now][1]=ch[pre][1]; 27 if(o==-1) return;bool c=w&(1<<o); 28 insert(ch[now][c],ch[pre][c],w,o-1); 29 } 30 int query(int now,int pre,int w,int o) 31 { 32 if(o==-1) return 0; 33 bool c=w&(1<<o); 34 int tmp=val[ch[now][c^1]]-val[ch[pre][c^1]]; 35 if(tmp) return query(ch[now][c^1],ch[pre][c^1],w,o-1)+(1<<o); 36 else return query(ch[now][c],ch[pre][c],w,o-1); 37 } 38 }T; 39 40 void insert(int node,int l,int r,int l1,int r1,int id) 41 { 42 if(l1>r1) return; 43 if(l1<=l&&r1>=r) {seg[node].push_back(id);return;} 44 int mid=(l+r)/2; 45 if(l1<=mid) insert(ls,l,mid,l1,r1,id); 46 if(r1>mid) insert(rs,mid+1,r,l1,r1,id); 47 } 48 49 int get(int v) 50 { 51 int l=1,r=cnt,ans=0; 52 while(l<=r) 53 { 54 int mid=(l+r)/2; 55 if(f[mid]<=v) ans=mid,l=mid+1; 56 else r=mid-1; 57 } 58 return ans; 59 } 60 61 void cal(int node,int l,int r) 62 { 63 cnt=T.cnt=0; 64 for(int i=l;i<=r;i++) 65 { 66 f[++cnt]=q[i].s; 67 T.insert(rt[cnt],rt[cnt-1],q[i].v,17); 68 } 69 for(int i=0;i<seg[node].size();i++) 70 { 71 int id=seg[node][i]; 72 int l=get(p[id].l-1); 73 int r=get(p[id].r); 74 ans[id]=max(ans[id],T.query(rt[r],rt[l],p[id].x,17)); 75 } 76 } 77 78 void solve(int node,int l,int r,int l1,int r1) 79 { 80 if(l1>r1) return; 81 cal(node,l,r); 82 if(l==r) return; 83 int mid=(l+r)/2,t1=0,t2=0; 84 for(int i=l1;i<=r1;i++) 85 { 86 if(q[i].t<=mid) tmp1[++t1]=q[i]; 87 else tmp2[++t2]=q[i]; 88 } 89 for(int i=1;i<=t1;i++) q[i+l1-1]=tmp1[i]; 90 for(int i=1;i<=t2;i++) q[i+l1-1+t1]=tmp2[i]; 91 solve(ls,l,mid,l1,l1+t1-1); 92 solve(rs,mid+1,r,l1+t1,r1); 93 } 94 95 int main() 96 { 97 scanf("%d%d",&n,&m); 98 for(int i=1;i<=n;i++) 99 { 100 int x;scanf("%d",&x); 101 T.insert(rt[i],rt[i-1],x,17); 102 } 103 for(int i=1;i<=m;i++) 104 { 105 int opt;scanf("%d",&opt); 106 if(!opt) 107 { 108 int s,v;scanf("%d%d",&s,&v); 109 cnt1++;q[cnt1]=(CG){s,v,cnt1}; 110 } 111 else 112 { 113 int l,r,x,d;scanf("%d%d%d%d",&l,&r,&x,&d); 114 ans[++cnt2]=T.query(rt[r],rt[l-1],x,17); 115 p[cnt2]=(ASK){l,r,max(1,cnt1-d+1),cnt1,x}; 116 } 117 } 118 for(int i=1;i<=cnt2;i++) 119 insert(1,1,cnt1,p[i].l1,p[i].r1,i); 120 sort(q+1,q+1+cnt1,cmp); 121 solve(1,1,cnt1,1,cnt1); 122 for(int i=1;i<=cnt2;i++) printf("%d\n",ans[i]); 123 return 0; 124 }