Connecting...

P4135 作诗 - 洛谷解题报告

P4135 作诗 - 洛谷解题报告

正常解法不好维护。标签说分块。

初看这题,复杂度瓶颈在于查询、预处理。

我们维护整块的答案,ans[i][j] 表示 \(block_i\sim block_j\) 间的答案。

这样我们每次询问求答案的时候相当于做了根号分治,单次查询复杂度 \(O(\sqrt{n})\)

查询解决了,我们怎么预处理?

我们不能枚举两块和颜色去合并,我们这里是 \(\sqrt{n}\sqrt{n}\sqrt{n}\) 递推去做的。

code:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5;
int n,m,c,a[maxn+19];
int block,tot,bel[maxn+10],l[maxn+10],r[maxn+10],num[350][maxn+10]/*num[i][j]block_i中j的次数*/,ans[350][350]/*ans[i][j]block_i~j中ans*/,cnt[maxn+10]/*对数字i进行累计*/;
void init(){
	block=sqrt(n);
	tot=n/block;if(n%block)tot++;
	for(int i=1;i<=n;++i){
		bel[i]=(i-1)/block+1;
	}
	for(int i=1;i<=tot;++i){
		l[i]=(i-1)*block+1;
		r[i]=i*block;
	}r[tot]=n;
	for(int i=1;i<=tot;++i){
		for(int j=l[i];j<=r[i];++j) num[i][a[j]]++;
		for(int j=0;j<=c;++j) num[i][j]+=num[i-1][j];
	}
	for(int i=1;i<=tot;++i){
		for(int j=i;j<=tot;++j){
			ans[i][j]=ans[i][j-1];
			for(int k=l[j];k<=r[j];++k){
				cnt[a[k]]++;
				if(cnt[a[k]]%2==0)ans[i][j]++;
				else if(cnt[a[k]]!=1)ans[i][j]--;
			}
		}
		memset(cnt,0,sizeof cnt);
	}
}
int q(int x,int y){//获得中间block的值 之后向两边拓展 因此要带上中间的值 
	memset(cnt,0,sizeof cnt);
	int t1=bel[x],t2=bel[y],tmp=0;
//	if(t2-t1<=1){//等价写法 
//		for(int i=x;i<=y;++i){
//			cnt[a[i]]++;
//			if(cnt[a[i]]%2==0)tmp++;
//			else if(cnt[a[i]]!=1)tmp--;
//		}
//		for(int i=x;i<=y;++i)cnt[a[i]]--;
//		return tmp;
//	}
//	tmp=ans[t1+1][t2-1];
//	for(int i=x;i<=r[t1];++i){
//		cnt[a[i]]++;
//		if((cnt[a[i]]+num[t2-1][a[i]]-num[t1][a[i]])%2==0)tmp++;
//		else if(cnt[a[i]]+num[t2-1][a[i]]-num[t1][a[i]]!=1) tmp--;
//	}
//	for(int i=l[t2];i<=y;++i){
//		cnt[a[i]]++;
//		if((cnt[a[i]]+num[t2-1][a[i]]-num[t1][a[i]])%2==0)tmp++;
//		else if(cnt[a[i]]+num[t2-1][a[i]]-num[t1][a[i]]!=1) tmp--;
//	}
//	for(int i=x;i<=min(y,r[t1]);++i)cnt[a[i]]--;
//	for(int i=l[t2];i<=y;++i)cnt[a[i]]--;
//	return tmp;
	for(int i=x;i<=min(y,r[t1]);++i){
		cnt[a[i]]++;
		if((cnt[a[i]]+(t1!=t2)*(num[t2-1][a[i]]-num[t1][a[i]]))%2==0)tmp++;
		else if(cnt[a[i]]+(t1!=t2)*(num[t2-1][a[i]]-num[t1][a[i]])!=1) tmp--;
	}
	if(t1!=t2) {
		for(int i=l[t2];i<=y;++i){
			cnt[a[i]]++;
			if((cnt[a[i]]+num[t2-1][a[i]]-num[t1][a[i]])%2==0)tmp++;
			else if(cnt[a[i]]+num[t2-1][a[i]]-num[t1][a[i]]!=1) tmp--;
		}tmp+=ans[t1+1][t2-1];
	}
	for(int i=x;i<=min(y,r[t1]);++i)cnt[a[i]]--;
	if(t1!=t2) for(int i=l[t2];i<=y;++i)cnt[a[i]]--;
	return tmp;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>c>>m;
	for(int i=1;i<=n;++i)cin>>a[i];
	init();
	int ans=0;
	for(int i=1;i<=m;++i){
		int x,y;
		cin>>x>>y;
		x=(x+ans)%n+1;
		y=(y+ans)%n+1;
		if(x>y)swap(x,y);
		ans=q(x,y);
		cout<<ans<<"\n";
	}
	return 0;
}
posted @ 2025-02-10 16:27  余亦宸  阅读(11)  评论(0)    收藏  举报