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

浙公网安备 33010602011771号