BZOJ4137 & 洛谷4585:[FJOI2015]火星商店问题
https://www.lydsy.com/JudgeOnline/problem.php?id=4137
https://www.luogu.org/problemnew/show/P4585
火星上的一条商业街里按照商店的编号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。
参考:https://blog.csdn.net/lvzelong2014/article/details/78688727
继续练习线段树分治,虽然还是离不开题解但是已经知道拿什么分治了。
以及越来越深感线段树分治并不是线段树这一个事实了,开个专栏吧。
显然d的存在使得一些商品被“撤销”了,但是每个人的d都是不同的,我们就没法把商品放到线段树上。
于是反其道而行之,把人扔到线段树上,把商品放到线段树上跑。
然后每次询问异或最大值就是可持久化trie了。
PS:时刻注意这里面有两个量:商品所在的商店,以及商品上货时间。不要搞混了。
我们预先按照商店排序,然后根据当前的时间区间再重新分配即可(有点像整体二分)。
#include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cctype> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=1e5+5; const int B=17; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct data{ int l,r,x,L,R; }p[N]; struct good{ int s,v,t; }q[N],tmpl[N],tmpr[N]; struct node{ int son[2],sum; }tr[N*40]; int n,m,pcnt,qcnt,ans[N],rt[N],num[N],pool; vector<int>seg[N*4]; inline bool cmp(good a,good b){ return a.s<b.s; } void insert(int y,int &x,int k,int now){ tr[x=++pool]=tr[y]; tr[x].sum++; if(now<0)return; bool p=k&(1<<now); insert(tr[y].son[p],tr[x].son[p],k,now-1); return; } int query(int nl,int nr,int k,int now){ if(now<0)return 0; bool p=k&(1<<now); int delta=tr[tr[nr].son[p^1]].sum-tr[tr[nl].son[p^1]].sum; if(delta>0)return (1<<now)+query(tr[nl].son[p^1],tr[nr].son[p^1],k,now-1); else return query(tr[nl].son[p],tr[nr].son[p],k,now-1); } void add(int a,int l,int r,int l1,int r1,int x){ if(r<l1||r1<l)return; if(l1<=l&&r<=r1){ seg[a].push_back(x);return; } int mid=(l+r)>>1; add(a<<1,l,mid,l1,r1,x);add(a<<1|1,mid+1,r,l1,r1,x); } int find(int l,int r,int k){ l--; while(l<r){ int mid=(l+r+1)>>1; if(num[mid]<=k)l=mid; else r=mid-1; } return l; } void work(int a,int l,int r){ pool=0;int cnt=0; for(int i=l;i<=r;i++){ num[++cnt]=q[i].s; insert(rt[cnt-1],rt[cnt],q[i].v,B); } for(int i=0;i<seg[a].size();i++){ int id=seg[a][i]; int L=find(1,cnt,p[id].l-1),R=find(1,cnt,p[id].r); ans[id]=max(ans[id],query(rt[L],rt[R],p[id].x,B)); } } void divide(int a,int l,int r,int l1,int r1){ int mid=(l+r)>>1,len1=0,len2=0; work(a,l1,r1); for(int i=l1;i<=r1;i++){ if(q[i].t<=mid)tmpl[len1++]=q[i]; else tmpr[len2++]=q[i]; } for(int i=0;i<len1;i++)q[i+l1]=tmpl[i]; for(int i=0;i<len2;i++)q[i+l1+len1]=tmpr[i]; if(l==r)return; divide(a<<1,l,mid,l1,l1+len1-1); divide(a<<1|1,mid+1,r,l1+len1,r1); } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++)insert(rt[i-1],rt[i],read(),B); for(int i=1;i<=m;i++){ int op=read(); if(!op){ q[++qcnt].s=read();q[qcnt].v=read(); q[qcnt].t=qcnt; }else{ p[++pcnt].l=read();p[pcnt].r=read(); p[pcnt].x=read();int d=read(); p[pcnt].L=max(qcnt-d+1,1);p[pcnt].R=qcnt; ans[pcnt]=query(rt[p[pcnt].l-1],rt[p[pcnt].r],p[pcnt].x,B); } } for(int i=1;i<=pcnt;i++)add(1,1,qcnt,p[i].L,p[i].R,i); sort(q+1,q+qcnt+1,cmp); divide(1,1,qcnt,1,qcnt); for(int i=1;i<=pcnt;i++)printf("%d\n",ans[i]); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++