题解:P13983 数列分块入门 8
Zhangxm2012 · · 题解
非常好,LOJ 上的题洛谷有了(双倍经验)。
既然标题写的是分块,那就用分块做吧。分块的时间复杂度为
若记块长为
- 若
l,r 在同一块内,最坏复杂度为O(s) ; - 若
l,r 不在同一块内,分三块计算:以l 为开头的不完整的一段、中间的完整块、和以r 为结尾的不完整的一段,最坏复杂度为O(\frac{n}{s}+s) - 综上,最坏复杂度为
O(\frac{n}{s}+s) 在s=\sqrt{n} 时取到最小值O(\sqrt{n}) 。
本题的数据范围为
好的,回归正题。
因为此题有区间覆盖,不难想到给每个区间打标记,
修改的时候一起统计:以
第二个也差不多:枚举所有的块,若是整块就直接加,否则再暴力循环统计即可,注意
#include<bits/stdc++.h>
using namespace std;
const int N=5004;
int n,m,k,a[N*N],blk[N],f[N],ans;
void U(int l,int r,int x){
int kk=l/k;
if(!f[kk]){
for(int i=l;i<=r;i++){
if(a[i]==x){
ans++;
}
a[i]=x;
}
}
else{
if(blk[kk]==x){
ans+=(r-l+1);
}
else{
for(int i=kk*k;i<(kk+1)*k;i++){
a[i]=blk[kk];
}
for(int i=l;i<=r;i++){
a[i]=x;
}
f[kk]=0;
}
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n;
k=sqrt(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
int l,r,c;
ans=0;
cin>>l>>r>>c;
l--,r--;
if(l/k==r/k){
U(l,r,c);
}
else{
U(l,(l/k+1)*k-1,c);
U(r/k*k,r,c);
for(int i=l/k+1;i<r/k;i++){
if(f[i]==0){
for(int j=i*k;j<i*k+k;j++){
if(a[j]==c){
ans++;
}
}
blk[i]=c;
f[i]=1;
}
else{
if(blk[i]==c){
ans+=k;
}
else{
blk[i]=c;
}
}
}
}
cout<<ans<<'\n';
}
return 0;
}