1. 程式人生 > 其它 >P7470 [NOI Online 2021 提高組] 島嶼探險

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=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;
}