P7470 [NOI Online 2021 提高组] 岛屿探险
FxorG
2021-07-30 22:19:15
**不一定正确!提供一个三合一才能过的分块**
$$ a_i \ xor\ c_j \le min(b_i,d_j)$$
$$ a_i \ xor \ c_j \le b_i$$
$$ a_i \ xor \ c_j \le d_j$$
$$a_i \ xor \ c_j \le d_j$$
可以考虑 $c_j,d_j=0$ 那么 $a_i=0$。
$c_j=1,dj=0,ai=1$。
$c_j=0,d_j=1,a_i=1/0$ 如果选 $1$ 的话就接着跳, $0$ 就加上左子树的所有的元素个数。
$c_j=1,d_j=1,a_i=1/0$ $0$ 接着跳,加上 $1$ 那边子树的元素个数。
然后,区间就可持久化 01-trie。
$$ a_i \ xor \ c_j \le b_i$$
$$ c_j \ xor \ a_i \le b_i$$
$b_i,a_i$ 作为询问 就一样跳 然后整个子树可以就加计数器 一个询问符合的 $c_j$ 就是 $c_j$ 到根的路径计数器和。
可以可持久化,对于每一个 $c_j$ 去拆 $[1,r]-[1,l-1]$ 就是答案。
我们需要保证查询的时候 $a_i,b_i$ 都已经刚刚好更新完毕了,这个将 $a_i,b_i$ 的加计数器也认为操作,右端点是 $i$,然后按右端点排序就可以。
**先修改后询问!**
那么,如何分离出 $[L,x],[x+1,R]$ 使得 $[L,x]$ 是 $min\{b_i\}\ge d,i\in[L,x]$?
实际上直接分块就好了,块内从小到大排序,并且我们可以将询问离线按 $d$ 排,这样每次块内 $x$ 不降,可以双指针优化。
算下复杂度,令 $T$ 为块长。
$O(\dfrac{n}{T}T\log T+mT+\dfrac{n}{T}m\log(\dfrac{n}{T}m)+\dfrac{n}{T}m\log w)$
第一个为预处理块的复杂度,第二个为在线处理 $d\le b$ 的复杂度,第三个为离线完操作+排序的复杂度,因为有 $\dfrac{n}{T}$ 个块,假如每次每个块都被覆盖到,那么会有 $m$ 次。最后一个是处理这些操作的复杂度。
**关于块长**,我们发现瓶颈是 $\dfrac{n}{T}m\log(\dfrac{n}{T}m)$,所以我们让 $T$ 尽可能大,实测在 $1750$ 最优。
[评测记录](https://www.luogu.com.cn/record/54653671)
$\text{Code}$
```cpp
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#define ll long long
using namespace std;
int rd() {
int f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
ll lrd() {
ll f=1,sum=0; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return sum*f;
}
void pr(int x) {
if(x<0) {putchar('-');x=-x;}
if(x>9) pr(x/10);
putchar(x%10+'0');
}
void lpr(ll x) {
if(x<0) {putchar('-');x=-x;}
if(x>9) pr(x/10);
putchar(x%10+'0');
}
/*
有区间之后枚举块
之前将所有c加入trie
考虑块排序后的区间所对应的 这个可以在分块build的时候处理出来
*/
#define N (int)(1e5+2)
#define M 80
#define il inline
int ans[N],son[2][N*30],sum[N*30];
int cnt[N],rid[N],a[N],b[N],C[N],L[M],R[M],id[N];
int n,m,bl,tot=1;
struct ques {
int l,r,uid,yx;
}q[N*M]; int qtot=0;
struct node {
int x,y;
}tmp[1752];
int B[M][1752],rt[N],rttot;
bool cmp(node x,node y) {
return x.x<y.x;
}
il void ins(int x) {
int pre=rt[rttot]; rt[++rttot]=++tot;
for(int i=24;i>=0;i--) {
int c=(x>>i)&1;
sum[tot]=sum[pre]+1;
son[c^1][tot]=son[c^1][pre];
son[c][tot]=tot+1; ++tot;
pre=son[c][pre];
}
sum[tot]=sum[pre]+1;
}
il int query(int l,int r,int c,int d) {
l=rt[l-1]; r=rt[r];
int res=0;
for(int i=24;i>=0;i--) {
int r1=(c>>i)&1,r2=(d>>i)&1;
if(r2) res+=sum[son[r1][r]]-sum[son[r1][l]];
if(!r1&&!r2) l=son[0][l],r=son[0][r];
if(r1&&!r2) l=son[1][l],r=son[1][r];
if(!r1&&r2) l=son[1][l],r=son[1][r];
if(r1&&r2) l=son[0][l],r=son[0][r];
}
res+=sum[r]-sum[l];
return res;
}
il void build(int x) {
for(int i=L[x];i<=R[x];++i) {
tmp[i-L[x]+1].x=b[i]; tmp[i-L[x]+1].y=i;
}
sort(tmp+1,tmp+1+R[x]-L[x]+1,cmp);
for(int i=1;i<=R[x]-L[x]+1;++i) {
B[x][i]=tmp[i].x; rid[L[x]+i-1]=tmp[i].y;
}
cnt[x]=L[x];
}
il void update(int l,int r,int c,int d,int uid) {
if(id[l]==id[r]) {
for(int i=l;i<=r;++i) ans[uid]+=((a[i]^c)<=min(b[i],d));
} else {
for(int i=l;i<=R[id[l]];++i) ans[uid]+=((a[i]^c)<=min(b[i],d));
for(int i=L[id[r]];i<=r;++i) ans[uid]+=((a[i]^c)<=min(b[i],d));
for(int i=id[l]+1;i<id[r];++i) {
while(cnt[i]<R[i]&&B[i][cnt[i]-L[i]+1]<=d) ++cnt[i];
if(B[i][cnt[i]-L[i]+1]<d) {
q[++qtot]=ques{1,L[i]-1,uid,2}; q[++qtot]=ques{1,R[i],uid,3};
} else { //L[i]~cnt[i]-1 cnt[i]-R[i]
if(L[i]<=cnt[i]-1) q[++qtot]=ques{1,L[i]-1,uid,2},q[++qtot]=ques{1,cnt[i]-1,uid,3};
ans[uid]+=query(cnt[i],R[i],c,d);
}
}
}
}
bool cmp2(ques x,ques y) {
return x.r==y.r?x.yx<y.yx:x.r<y.r;
}
il void insC(int x) {
int p=1;
for(int i=24;i>=0;i--) {
int c=(x>>i)&1;
if(!son[c][p]) son[c][p]=++tot;
p=son[c][p];
}
}
il void solve(int x,int y) {
int p=1;
for(int i=24;i>=0;i--) {
int r1=(x>>i)&1,r2=(y>>i)&1;
if(r2) sum[son[r1][p]]++;
if(r1&&r2) p=son[0][p];
if(!r1&&r2) p=son[1][p];
if(!r1&&!r2) p=son[0][p];
if(r1&&!r2) p=son[1][p];
}
++sum[p];
}
il int query(int x) {
int res=0,p=1;
for(int i=24;i>=0;i--) {
int c=(x>>i)&1;
res+=sum[p]; p=son[c][p];
}
res+=sum[p];
return res;
}
struct ask{
int l,r,c,d,id;
}A[N];
il bool cmp3(ask x,ask y) {
return x.d<y.d;
}
int st[20][N];
il int st_qry(int l,int r) {
int qwq=log2(r-l+1);
return max(st[qwq][l],st[qwq][r-(1<<qwq)+1]);
}
il void solve1() {
for(int i=1;i<=m;++i) {
q[++qtot]=ques{1,A[i].l-1,i,2}; q[++qtot]=ques{1,A[i].r,i,3};
}
for(int i=1;i<=n;++i) q[++qtot]=ques{0,i,i,1};
sort(q+1,q+1+qtot,cmp2);
for(int i=1;i<=m;++i) insC(C[i]);
for(int i=1;i<=qtot;++i) {
if(q[i].yx==1) {
solve(a[q[i].uid],b[q[i].uid]);
} else if(q[i].yx==2) {
ans[q[i].uid]-=query(C[q[i].uid]);
} else {
ans[q[i].uid]+=query(C[q[i].uid]);
}
}
for(int i=1;i<=m;++i) pr(ans[i]),puts("");
}
namespace solve2 {
struct node {
int x,id;
}T[N];
bool cmp(node x,node y) {
return x.x<y.x;
} int tmp[N];
void sol() {
for(int i=1;i<=n;i++) T[i].x=b[i],T[i].id=i;
sort(T+1,T+1+n,cmp);for(int i=1;i<=n;i++) tmp[i]=b[i]; sort(tmp+1,tmp+1+n);
for(int i=1;i<=n;i++) ins(a[T[i].id]);
for(int i=1;i<=m;i++) {
int qwq=upper_bound(tmp+1,tmp+1+n,A[i].d)-tmp-1;
if(qwq) q[++qtot]=ques{1,qwq,i,1};
if(qwq+1<=n) ans[A[i].id]+=query(qwq+1,n,A[i].c,A[i].d);
}
for(int i=1;i<=tot;i++) sum[i]=son[0][i]=son[1][i]=0; tot=1;
for(int i=1;i<=m;i++) insC(C[i]);
for(int i=1;i<=n;i++) q[++qtot]=ques{1,i,T[i].id,0};
sort(q+1,q+1+qtot,cmp2);
for(int i=1;i<=qtot;i++) {
if(q[i].yx==0) solve(a[q[i].uid],b[q[i].uid]);
else ans[q[i].uid]+=query(C[q[i].uid]);
}
for(int i=1;i<=m;i++) pr(ans[i]),puts("");
}
}
int main() {
n=rd(); m=rd(); bl=1750;
for(int i=1;i<=n;++i) a[i]=rd(),b[i]=rd();
for(int i=1;i<=n;++i) st[0][i]=b[i];
for(int i=1;i<=18;++i)
for(int j=1;j+(1<<i)-1<=n;j++)
st[i][j]=max(st[i-1][j],st[i-1][j+(1<<(i-1))]);
bool fl=1,fl2=1;
for(int i=1;i<=m;++i) {
A[i].l=rd(); A[i].r=rd(); A[i].c=C[i]=rd(); A[i].d=rd(); A[i].id=i;
if(A[i].d<st_qry(A[i].l,A[i].r)) fl=0;
if(A[i].l!=1||A[i].r!=n) fl2=0;
}
if(fl) {
solve1(); return 0;
}
if(fl2) {
solve2::sol(); return 0;
}
for(int i=1;i<=n;++i) id[i]=(i-1)/bl+1;
for(int i=1;i<=id[n];++i) L[i]=(i-1)*bl+1,R[i]=i*bl; R[id[n]]=n;
for(int i=1;i<=id[n];++i) build(i);
for(int i=1;i<=n;++i) ins(a[rid[i]]);
sort(A+1,A+1+m,cmp3);
for(int i=1;i<=m;++i) update(A[i].l,A[i].r,A[i].c,A[i].d,A[i].id);
for(int i=1;i<=n;++i) q[++qtot]=ques{rid[i],i,0,1};
sort(q+1,q+1+qtot,cmp2);
for(int i=1;i<=tot;i++) sum[i]=0,son[0][i]=son[1][i]=0; tot=1;
for(int i=1;i<=m;++i) insC(C[i]);
for(int i=1;i<=qtot;++i) {
if(q[i].yx==1) {
solve(a[q[i].l],b[q[i].l]);
} else if(q[i].yx==2) {
ans[q[i].uid]-=query(C[q[i].uid]);
} else {
ans[q[i].uid]+=query(C[q[i].uid]);
}
}
for(int i=1;i<=m;++i) pr(ans[i]),puts("");
return 0;
}
```