【BZOJ】2821: 作诗-分块 & 2724[Violet 6]蒲公英

传送门:
bzoj2821
bzoj2724


bzoj2821

大胆猜想分块:预处理每块值的桶,及 f [ i ] [ j ] f[i][j] f[i][j]表示第 i − j i-j ij块的答案。

复杂度存疑,遂证明之:预处理 O ( n n ) O(n\sqrt n) O(nn ),询问散块最多只涉及 2 n 2\sqrt n 2n 个值,答案=这 2 n 2\sqrt n 2n 在散整块中出现情况+ f [ b e l l + 1 ] [ b e l r − 1 ] f[bel_l+1][bel_r-1] f[bell+1][belr1],复杂度同样为 O ( n n ) O(n\sqrt n) O(nn )

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,M=318;

int n,c,m,blk,ql[M],qr[M],cnt,tim,ans;
int a[M],f[M][N],g[M][M],vs[N],cot[N],q[N],tot;

int main(){
	int i,j,k,v,t,lim,x,y,l,r;
	scanf("%d%d%d",&n,&c,&m);
	blk=sqrt(n);cnt=(n-1)/blk+1;
	for(i=1;i<=n;++i) scanf("%d",&a[i]);
	for(i=1;i<=cnt;++i){
		ql[i]=(i-1)*blk+1;qr[i]=(i^cnt)?i*blk:n;
		for(j=ql[i],lim=qr[i];j<=lim;++j)
		 for(k=i,v=a[j];k<=cnt;++k) f[k][v]++;
	}
	for(i=1;i<=cnt;++i){
		for(v=0,j=i;j<=cnt;++j){
			for(k=ql[j],lim=qr[j];k<=lim;++k){
				cot[a[k]]++;
				if(!(cot[a[k]]&1)) v++;else if(cot[a[k]]>1) v--;
			}
			g[i][j]=v;
		}
		memset(cot,0,sizeof(cot));
	}
	for(tim=cnt;m;--m){
		scanf("%d%d",&x,&y);
		x=(x+ans)%n+1;y=(y+ans)%n+1;if(x>y) swap(x,y);
		l=(x-1)/blk+1;r=(y-1)/blk+1;tim++;tot=ans=0;
		for(lim=min(qr[l],y),i=x;i<=lim;++i){
			if(vs[a[i]]!=tim) q[++tot]=a[i],vs[a[i]]=tim;
			cot[a[i]]++;
		}
		if(l^r)
		    for(i=ql[r];i<=y;++i){
				if(vs[a[i]]!=tim) q[++tot]=a[i],vs[a[i]]=tim;
				cot[a[i]]++;
			}
		if(l+2<=r){
			ans=g[l+1][r-1];
			for(i=1;i<=tot;++i){
				x=f[r-1][q[i]]-f[l][q[i]];y=cot[q[i]]&1;
				if(!x) ans+=(y?0:1);
				else if(!(x&1)) ans-=(y?1:0);
				else ans+=(y?1:0);
			}
		}else for(i=1;i<=tot;++i) ans+=(cot[q[i]]&1)?0:1;
		for(i=1;i<=tot;++i) cot[q[i]]=0;
		printf("%d\n",ans);
	}
	return 0;
}

bzoj2724

维护区间众数,和上面十分类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值