CF765F. Souvenirs

发布时间 2023-06-25 17:27:02作者: xx019

压位 trie 好厉害。

显然加一个数很好维护,删一个数有点不好做,考虑回滚莫队。用平衡树维护数的集合,每次插入之前用前驱/后继与插入数的差更新一下答案,可以 \(O(n\sqrt{n}\log n)\),会 Time limit exceeded on test 7 or 8。看上去我们已经优化到极限了,怎么办呢?

显然莫队的 \(n\sqrt{n}\) 我们没法动它,只能在这个 \(\log n\) 上做文章了:考虑用压位 trie 代替平衡树,这样就优化到了 \(O(n\sqrt{n}\log_{64} n)\),基本可以当成常数。

其实光做法没什么好说的,主要还是实现。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int inf=1e9; 
inline int read(){
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
#define clz(x) (__builtin_clzll(x))
#define ctz(x) (__builtin_ctzll(x))
ull BUFF[1<<25],*BT=BUFF+sizeof(BUFF)/sizeof(ull);
ull *alloc(int siz){return BT-=siz;}
const int g=6,mod=(1<<g)-1;
int dep;ull *c[5];
void init(int siz){
	for(dep=1;;dep++){
		int cnt=(siz+(1ull<<g*dep)-1)>>g*dep;
		c[dep-1]=alloc(cnt);
		if(cnt==1)return;
	}
}	
void insert(int x){
	for(int i=0;i<dep;i++){
		ull p=1ull<<(x>>i*g&mod);
		if(c[i][x>>(i+1)*g]&p)return;
		c[i][x>>(i+1)*g]|=p;
	}
}
void erase(int x){
	for(int i=0;i<dep;i++)
		if(c[i][x>>(i+1)*g]&=~(1ull<<(x>>i*g&mod)))return;
}
int getpre(int x){
	for(int i=0;i<dep;i++){
		int cur=(x>>i*g)&mod;ull v=c[i][x>>(i+1)*g];
		if(v&((1ull<<cur)-1)){
			int res=x>>(i+1)*g<<(i+1)*g;res+=(mod-clz(v&((1ull<<cur)-1)))<<i*g;
			for(int j=i-1;j>=0;j--)res+=(mod-clz(c[j][res>>(j+1)*g]))<<j*g;
			return res;
		}
	}
	return -1;
}	
int getsuf(int x){
	for(int i=0;i<dep;i++){
		int cur=(x>>i*g)&mod;ull v=c[i][x>>(i+1)*g];
		if(v>>cur>1){
			int res=x>>(i+1)*g<<(i+1)*g;res+=(ctz(v>>(cur+1))+cur+1)<<i*g;
			for(int j=i-1;j>=0;j--)res+=ctz(c[j][res>>(j+1)*g])<<j*g;
			return res;
		}
	}
	return -1;
}
int a[300005],b[300005],B[300005];
int get(int x){
	int res=inf;
	if(B[x])return 0;
	int pre=getpre(x),suf=getsuf(x);
	if(pre!=-1)res=min(res,b[x]-b[pre]);
	if(suf!=-1)res=min(res,b[suf]-b[x]);
	return res;
}
int ask(int l,int r){
	int res=inf;
	for(int i=l;i<=r;i++){
		res=min(res,get(a[i])),B[a[i]]++;
		if(B[a[i]]==1)insert(a[i]);
	}
	for(int i=l;i<=r;i++){
		B[a[i]]--;
		if(B[a[i]]==0)erase(a[i]);
	}
	return res;
}
int bel[300005],bl[5005],br[5005];
struct Que{
	int l,r,id;
}q[300005];
int cmp(Que x,Que y){
	if(bel[x.l]^bel[y.l])return bel[x.l]<bel[y.l];
	return x.r<y.r;
}
int ans[300005];
signed main(){
	int n=read(),tot=0;
	for(int i=1;i<=n;i++)a[i]=b[++tot]=read();
	sort(b+1,b+tot+1);tot=unique(b+1,b+tot+1)-b-1;
	init(tot);
	for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
	int siz=(int)sqrt(n),num=(n+siz-1)/siz;
	for(int i=1;i<=n;i++)bel[i]=(i-1)/siz+1;
	for(int i=1;i<=num;i++)bl[i]=(i-1)*siz+1,br[i]=i*siz;
	br[num]=n;
	int m=read();
	for(int i=1,l,r;i<=m;i++)l=read(),r=read(),q[i]=(Que){l,r,i};
	sort(q+1,q+m+1,cmp);
	for(int i=1;i<=m;i++)if(bel[q[i].l]==bel[q[i].r])ans[q[i].id]=ask(q[i].l,q[i].r);
	for(int i=1,j=1;i<=num;i++){
		int L=br[i]+1,R=br[i],res=inf;
		while(j<=m){
			int l=q[j].l,r=q[j].r,id=q[j].id,tmp=inf;
			if(bel[l]!=i)break;
			if(bel[r]==i){j++;continue;}
			while(R<r){
				R++,res=min(res,get(a[R])),B[a[R]]++;
				if(B[a[R]]==1)insert(a[R]);
			}
			while(L>l){
				L--,tmp=min(tmp,get(a[L])),B[a[L]]++;
				if(B[a[L]]==1)insert(a[L]);
			}
			while(L<=br[i]){
				B[a[L]]--;
				if(B[a[L]]==0)erase(a[L]);
				L++;
			}
			ans[id]=min(res,tmp);
			j++;
		}
		while(R>br[i]){
			B[a[R]]--;
			if(B[a[R]]==0)erase(a[R]);
			R--;
		}
	}
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}