https://acm.hdu.edu.cn/showproblem.php?pid=6964
给定一数列,每次查询$(l,r)$,找到数列中位于该区间内的数$c$满足$a\, xor c\le b$,求这样的数的个数(要求数不能相同)。
SB题但是我不太会套路,来补一下。
显然是建Trie,然后由于求的是不同的数所以很快想到可持久化Trie+每个节点存当前子树中拥有那些数,然后空间爆炸。
此时我比赛时想的是莫队(虽然没写也不知道对不对不过大概跑不过去)。
对每个节点记录其子树所存所有的数的话,只可能是普通Trie(这样可以保证空间为$O(nlogn)$),然后问题在于如何实现查询。
显然比较从高位往低位比较,这个相信大家都会,问题在于如何去掉相同的数,做法就是记录和它相同的下一个数的位置,如果当前的数在区间中且下一个与它相同的数不在区间中,那我们就统计这个数。
不妨设查询区间为$(L,R)$,这个数的位置与与它相同的下一个数的位置所组成的二元组为$(l,r)$,则我们要满足$L\le l \le R < r$,可以用二维数点来做,即树状数组实现,对$r$进行排序,然后每次查询为$qry(R)-qry(L-1)$。
复杂度$O(nlog^2n)$。
#include<cmath> #include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N=1e5+5; const int B=16; 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 val{ int x,y,id; val(){} val(int _x,int _y,int _id){ x=_x;y=_y;id=_id; } bool operator <(const val &b)const{ return x>b.x||(x==b.x&&id>b.id); } }; struct node{ int son[2]; vector<val>v; }tr[N*B]; int head[N],nxt[N]; int pool,rt,a[N],n,m; void insert(int x,int k,int pos,int now){ tr[x].v.push_back(val(nxt[pos],pos,0)); if(now<0)return; bool p=k&(1<<now); if(!tr[x].son[p])tr[x].son[p]=++pool; insert(tr[x].son[p],k,pos,now-1); } void query(int x,int l,int r,int _a,int _b,int pos,int now){ if(!x)return; if(now<0)tr[x].v.push_back(val(r,l,pos)); bool p=_a&(1<<now),pp=_b&(1<<now); if(pp&&tr[x].son[p])tr[tr[x].son[p]].v.push_back(val(r,l,pos)); query(tr[x].son[p^pp],l,r,_a,_b,pos,now-1); } void init(){ rt=++pool; } int t[N]; inline int lowbit(int x){return x&(-x);} void add(int x,int y){ for(int i=x;i<=n+1;i+=lowbit(i))t[i]+=y; } int qry(int x){ int res=0; for(int i=x;i>0;i-=lowbit(i))res+=t[i]; return res; } int ans[N]; int main(){ init(); n=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=n;i>=1;i--){ if(!head[a[i]])nxt[i]=n+1; else nxt[i]=head[a[i]]; head[a[i]]=i; } for(int i=1;i<=n;i++)insert(rt,a[i],i,B); m=read(); for(int i=1;i<=m;i++){ int _l=read(),_r=read(),_a=read(),_b=read(); query(rt,_l,_r,_a,_b,i,B); } for(int i=1;i<=pool;i++){ sort(tr[i].v.begin(),tr[i].v.end()); for(int j=0;j<tr[i].v.size();j++){ if(tr[i].v[j].id){ ans[tr[i].v[j].id]+=qry(tr[i].v[j].x)-qry(tr[i].v[j].y-1); }else{ add(tr[i].v[j].y,1); } } for(int j=0;j<tr[i].v.size();j++){ if(!tr[i].v[j].id)add(tr[i].v[j].y,-1); } } for(int i=1;i<=m;i++){ printf("%d\n",ans[i]); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++