[FJOI2015]火星商店问题

lindongli2004

2020-05-09 00:07:35

Solution

标签:线段树 + $01-trie$ 首先,看到与 $x$ 的异或值最大,我们应该立即想到 $01-tire$ 的贪心算法,即: - 我们把已有的数字从第 $30$ 位到第 $1$ 位按照二进制,依次插入到 $tire$ 树中。 - 查询数字 $x$ 时,从第 $30$ 位到第 $1$ 位贪心:设当前二进制位为 $y$ ,那么数字 $x$ 的这个二进制位为 th=x>>y&1,那么如果当前 $trie$ 树上有 th^1 这个分支,说明 $x$ 在 $y$ 这个二进制位上可以取到值,所以 $ans+=(1<<y)$,递归到 th^1 这个分支,否则就递归到 th 这个分支,继续往下找。 现在我们就有了一个显然的暴力:每个商店维护一个 $01-trie$,查询时从 $l$ 枚举到 $r$, 把结果取 $max$,修改时,我们可以在每个 $01-trie$ 的结点上记录:该结点最晚的修改时间 $dmx$,这样查询时,如果要进入的结点的 $dmx$ 小于最早的合法时限,那就 $return$ 即可。 总结一下上述操作:单点修改,区间查询,可以用线段树维护,线段树的每个结点维护这个区间内的所有数的 $01-trie$ ,实现用到了标记永久化的技巧。 时空复杂度:$O(n \;log n \;log\;max\{val\} )$。 下面是参考代码: ```cpp #include<iostream> #include<cstdio> using namespace std; const int MX=4e7,INF=1e9; int n,tot; struct Tire_01{ int c[MX][2],mx[MX]; // mx 记录的是该结点的最晚修改时间 inline void add(int k,int x,int d){ for(int i=20;i>=0;i--){ int th=x>>i&1; k=c[k][th]?c[k][th]:(c[k][th]=++tot); mx[k]=max(mx[k],d); } } inline int ask(int k,int x,int d){ int r=0; for(int i=20;i>=0;i--){ int th=x>>i&1; if(c[k][th^1] && mx[c[k][th^1]]>=d)r|=(1<<i),k=c[k][th^1]; else if(mx[c[k][th]]>=d)k=c[k][th]; else return r; } return r; } }tr; int query(int k,int l,int r,int ql,int qr,int x,int d){ if(ql<=l && qr>=r)return tr.ask(k,x,d); int mid=(l+r)>>1,ans=0; if(ql<=mid)ans=max(ans,query(k<<1,l,mid,ql,qr,x,d)); if(qr>mid) ans=max(ans,query(k<<1|1,mid+1,r,ql,qr,x,d)); return ans; } void change(int k,int l,int r,int x,int y,int d){ tr.add(k,y,d); if(l==r)return; int mid=(l+r)>>1; if(x<=mid)change(k<<1,l,mid,x,y,d); else change(k<<1|1,mid+1,r,x,y,d); } inline int read(){ int x=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){x=x*10+ch-'0';ch=getchar();} while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int main() { n=read(); int aq=read(); tot=n<<2; for(int i=1;i<=n;i++) change(1,1,n,i,read(),INF); int cnt=0; while(aq--){ int op=read(),l=read(),r=read(),x,y; if(!op)++cnt,change(1,1,n,l,r,cnt); else x=read(),y=read(),printf("%d\n",query(1,1,n,l,r,x,max(0,cnt-y+1))); } return 0; } ``` 小结:遇到题目要理清思路,找到突破口,顺藤摸瓜找到解决方案。