Codeforces 543E - Listening to Music(分块)

根号 log 做法。能过 CF 的数据,但过不了校内模拟赛的数据/tuu

考虑从 \(f(i,x)\)\(f(i+1,x)\) 的变化在哪里:少了个 \(a_i\) 多了个 \(a_{i+m}\),因此显然只有 \(x\) 在它俩中间才有 \(f(i,x)\ne f(i+1,x)\),即:

\[f(i+1,x)-f(i,x)=\begin{cases}-1&(a_i<x\le a_{i+m})\\1&(a_{i+m}<x\le a_i)\\0&\text{otherwise}\end{cases} \]

我们不妨记其为 \(g(i,x)\)。换句话说这个 \(g(i,x)\) 的贡献形式是一段区间。

而显然 \(f(j,x)=f(i,x)+\sum\limits_{k=i}^{j-1}g(k,x)\),因此询问等价于查询 \(f(l,x)\)\(g(l,x),g(l+1,x),\cdots,g(r-1,x)\) 的最小前缀和。由于空间 64MB(一眼沙东 OI problemprovidercreep),考虑分块,对于前者直接将区间中的数排个序 lower_bound 即可,对于后者将这个块内所有区间左右端点当作关键点离散化,然后对每一段分别求出 \(x\) 在这一段内的最小前缀和和总和即可。块长取 \(\sqrt{n\log n}\) 时最优。

const int MAXN=2e5;
const int BLK_SZ=900;
const int BLK_CNT=MAXN/BLK_SZ;
int n,m,typ,a[MAXN+5],b[MAXN+5],L[MAXN+5],R[MAXN+5],blk_sz,blk_cnt,bel[MAXN+5];
int calc_less(int l,int r,int x){
	if(bel[l]==bel[r]){
		int sum=0;
		for(int i=l;i<=r;i++)sum+=(a[i]<x);
		return sum;
	}else{
		int sum=0;
		for(int i=l;i<=R[bel[l]];i++)sum+=(a[i]<x);
		for(int i=L[bel[r]];i<=r;i++)sum+=(a[i]<x);
		for(int i=bel[l]+1;i<bel[r];i++){
			int pos=lower_bound(b+L[i],b+R[i]+1,x)-b;
			sum+=pos-L[i];
		}return sum;
	}
}
tuple<int,int,int>c[MAXN+5];
int key[BLK_CNT+5][BLK_SZ*2+5],uni[BLK_CNT+5][BLK_SZ*2+5];
int cnt[BLK_SZ+5],num[BLK_SZ+5];
int sum[BLK_CNT+5][BLK_SZ*2+5],mn[BLK_CNT+5][BLK_SZ*2+5];
int calc_mn(int l,int r,int x){
	if(bel[l]==bel[r]){
		int _sum=0,_mn=0;
		for(int i=l;i<=r;i++){
			if(get<0>(c[i])<=x&&x<=get<1>(c[i]))_sum+=get<2>(c[i]);
			chkmin(_mn,_sum);
		}return _mn;
	}else{
		int _sum=0,_mn=0;
		for(int i=l;i<=R[bel[l]];i++){
			if(get<0>(c[i])<=x&&x<=get<1>(c[i]))_sum+=get<2>(c[i]);
			chkmin(_mn,_sum);
		}
		for(int i=bel[l]+1;i<bel[r];i++){
			int pos=upper_bound(uni[i]+1,uni[i]+num[i]+1,x)-uni[i]-1;
			chkmin(_mn,_sum+mn[i][pos]);_sum+=sum[i][pos];
		}
		for(int i=L[bel[r]];i<=r;i++){
			if(get<0>(c[i])<=x&&x<=get<1>(c[i]))_sum+=get<2>(c[i]);
			chkmin(_mn,_sum);
		}
		return _mn;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
	blk_sz=BLK_SZ;blk_cnt=(n-1)/blk_sz+1;
	for(int i=1;i<=blk_cnt;i++){
		L[i]=(i-1)*blk_sz+1;R[i]=min(i*blk_sz,n);
		for(int j=L[i];j<=R[i];j++)bel[j]=i;
	}
	for(int i=1;i<=blk_cnt;i++)sort(b+L[i],b+R[i]+1);
	for(int i=1;i<=n-m;i++){
		if(a[i]<a[i+m])c[i]=mt(a[i]+1,a[i+m],-1);
		else if(a[i]>a[i+m])c[i]=mt(a[i+m]+1,a[i],1);
	}
	for(int i=1;i<=blk_cnt;i++){
		for(int j=L[i];j<=R[i];j++)if(get<2>(c[j]))
			key[i][++cnt[i]]=get<0>(c[j]),key[i][++cnt[i]]=get<1>(c[j])+1;
		key[i][++cnt[i]]=0;
		sort(key[i]+1,key[i]+cnt[i]+1);key[i][0]=-1;
		for(int j=1;j<=cnt[i];j++)if(key[i][j]!=key[i][j-1])uni[i][++num[i]]=key[i][j];
		for(int j=1;j<=num[i];j++){
			int SUM=0,MN=0;
			for(int k=L[i];k<=R[i];k++){
				if(get<0>(c[k])<=uni[i][j]&&uni[i][j]<=get<1>(c[k]))
					SUM+=get<2>(c[k]);
				chkmin(MN,SUM);
			}mn[i][j]=MN;sum[i][j]=SUM;
		}
	}
	int qu,lstans=0;scanf("%d",&qu);
	while(qu--){
		int l,r,x;scanf("%d%d%d",&l,&r,&x);x^=lstans;
		if(l==r)printf("%d\n",lstans=calc_less(l,l+m-1,x));
		else printf("%d\n",lstans=calc_less(l,l+m-1,x)+calc_mn(l,r-1,x));
	}
	return 0;
}
posted @ 2023-05-11 16:53  tzc_wk  阅读(44)  评论(3编辑  收藏  举报