P7470 [NOI Online 2021 提高組] 島嶼探險
**不一定正確!提供一個三合一才能過的分塊**
$$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}$
#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=