P7470-[NOI Online 2021 提高組]島嶼探險【Trie,CDQ分治】
阿新 • • 發佈:2021-09-01
正題
題目連結:https://www.luogu.com.cn/problem/P7470
題目大意
給出\(n\)個二元組\((a,b)\)。
\(q\)次詢問給出\((l,r,c,d)\)表示詢問\([l,r]\)中有多少二元組滿足\(c\ xor\ a\leq min(b,d)\)。
\(1\leq n,q\leq 10^5\)
解題思路
這個\(min\)一看就很迷,顯然是讓我們分兩種情況討論。
再把詢問拆一下,就變成了兩個條件\(pos\leq r/pos<l\)且\(b\leq d/b>d\)。
兩個偏序條件的話直接上\(CDQ\),然後考慮兩種情況怎麼處理。
- \(c\ xor\ a\leq b\)
- \(c\ xor\ a\leq d\):對於每組詢問在\(Trie\)上跑區間求和即可。
時間複雜度\(O(n\log^2 n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> using namespace std; const int N=1e5+10,M=N*24; struct node{ int w,l,id; }q[N<<1],a[N]; int n,m,tot,rt1,rt2,ans[N]; vector<node> v[N]; struct Trie1{ int cnt,ch[M][2],w[M]; void Clear(){rt1=0;cnt=0;return;} int Newp(){++cnt;ch[cnt][0]=ch[cnt][1]=w[cnt]=0;return cnt;} void Insert(int &x,int d,int l,int val){ if(!x)x=Newp(); if(d<0){w[x]++;return;} int c=(val>>d)&1; if((l>>d)&1){ Insert(ch[x][c^1],d-1,l,val); if(!ch[x][c])ch[x][c]=Newp(); w[ch[x][c]]++; } else Insert(ch[x][c],d-1,l,val); } int Ask(int x,int d,int val){ if(!x)return 0; if(d<0) return w[x]; int c=(val>>d)&1; return Ask(ch[x][c],d-1,val)+w[x]; } }T1; struct Trie2{ int cnt,ch[M][2],w[M]; void Clear(){rt2=0;cnt=0;return;} int Newp(){++cnt;ch[cnt][0]=ch[cnt][1]=w[cnt]=0;return cnt;} void Insert(int &x,int d,int val){ if(!x)x=Newp(); if(d<0){w[x]++;return;} int c=(val>>d)&1; Insert(ch[x][c],d-1,val); w[x]=w[ch[x][0]]+w[ch[x][1]]; return; } int Ask(int x,int d,int l,int val){ if(d<0)return w[x]; int c=(val>>d)&1; if((l>>d)&1) return Ask(ch[x][c^1],d-1,l,val)+w[ch[x][c]]; return Ask(ch[x][c],d-1,l,val); } }T2; bool cmp(node x,node y) {return x.l<y.l;} void CDQ(int l,int r){ if(l==r)return; int mid=(l+r)>>1; CDQ(l,mid); CDQ(mid+1,r); sort(a+l,a+mid+1,cmp); T1.Clear();T2.Clear();tot=0; for(int i=mid+1;i<=r;i++) for(int j=0;j<v[i].size();j++) q[++tot]=v[i][j]; sort(q+1,q+1+tot,cmp); for(int i=1,z=l;i<=tot;i++){ while(z<=mid&&a[z].l<=q[i].l) T1.Insert(rt1,23,a[z].l,a[z].w),z++; if(q[i].id<0)ans[-q[i].id]-=T1.Ask(rt1,23,q[i].w); else ans[q[i].id]+=T1.Ask(rt1,23,q[i].w); } for(int i=tot,z=mid;i>=1;i--){ while(z>=l&&a[z].l>q[i].l) T2.Insert(rt2,23,a[z].w),z--; if(q[i].id<0)ans[-q[i].id]-=T2.Ask(rt2,23,q[i].l,q[i].w); else ans[q[i].id]+=T2.Ask(rt2,23,q[i].l,q[i].w); } return; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d",&a[i].w,&a[i].l); for(int i=1;i<=m;i++){ int l,r,c,d; scanf("%d%d%d%d",&l,&r,&c,&d); v[l].push_back((node){c,d,-i}); v[r+1].push_back((node){c,d,i}); } sort(q+1,q+1+n,cmp); CDQ(1,n+1); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }