首页 > 其他分享 >CF765F. Souvenirs

CF765F. Souvenirs

时间:2023-06-25 17:37:25浏览次数:39  
标签:ch return int res Souvenirs -- CF765F mod

压位 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;
}

标签:ch,return,int,res,Souvenirs,--,CF765F,mod
From: https://www.cnblogs.com/xx019/p/17502423.html

相关文章

  • 洛谷P9035 Pont des souvenirs 题解
    题面很简洁,这里不做多说。70pts做法首先考虑到\(a_{n-1}\)和\(a_n\)两项是整个数列\(a\)中的最大的两项,所以若\(a_{n-1}+a_n\)不超过\(k+1\),则数列中任意两项......
  • CF765F Souvenirs 题解
    Preface在会压位Trie的前提下,本题最好想的做法应该是压位Trie+回滚莫队,可是竟然没人写这个做法的题解?Solution我们先转化题意:设\(a_i\)在\([l,r]\)中的前驱后继......
  • 【题解】CF808E Selling Souvenirs
    题意多重背包,但数据范围很大并且体积小于等于三。思路乱搞。很自然地考虑将物品按照体积分成三类。显然对于同一类的物品从最大开始取最优,那么有一个贪心的想法。直......
  • Souvenirs
    Souvenirs题目大意给出\(n\)以及一个长为\(n\)的序列\(a\)。给出\(m\),接下来\(m\)组询问。每组询问给出一个\(l,r\),你需要求出,对于\(i,j\in[l,r]\),且满足......
  • E. Selling Souvenirs 不会做
    ​​http://codeforces.com/contest/808/problem/E​​不理解为什么dp={cost,cnt1,cnt2}可以而dp={cost,cnt1,cnt2,cnt3}不可以上面那个不可以的例子是:  但是这......
  • CF765F
    分块。\(f[i][j]\):\(i\)一直到第\(i\)所在块\(x\)尾端,对\(x+1\simj\)块造成贡献/\(i\)一直到\(i\)所在块\(x\)开头,对\(j\simx-1\)块造成贡献。\(mn[i][j......