分块习题
P3203 [HNOI2010] 弹飞绵羊
虽然是
如果没有修改操作,可以
对于每个块里的点,预处理出它跳出这个块的步数,那么查询时就可以
修改一个点时,也就是
令
code
#include<bits/stdc++.h>
using namespace std;
const int N=200010,BB=5010;
int n,m,e[N];
int B,t,L[BB],R[BB],pos[N],f[N],lk[N];
void prework()
{
B=sqrt(n); t=n/B;
for(int i=1; i<=t; i++)
L[i]=(i-1)*B+1,R[i]=i*B;
if(R[t]<n)
t++,L[t]=R[t-1]+1,R[t]=n;
for(int i=1; i<=t; i++)
{
for(int j=R[i]; j>=L[i]; j--)
{
pos[j]=i;
if(j+e[j]>R[i])
f[j]=1,lk[j]=j+e[j];
else
f[j]=f[j+e[j]]+1,lk[j]=lk[j+e[j]];
}
}
}
void change(int x,int v)
{
int p=pos[x]; e[x]=v;
for(int i=R[p]; i>=L[p]; i--)
{
if(i+e[i]>R[p])
f[i]=1,lk[i]=i+e[i];
else
f[i]=f[i+e[i]]+1,lk[i]=lk[i+e[i]];
}
}
int ask(int x)
{
int p=pos[x],res=f[x];
for(int i=p+1,cur=lk[x]; i<=t; i++)
{
res+=f[cur];
cur=lk[cur];
}
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&e[i]);
prework();
scanf("%d",&m);
while(m--)
{
int op,s,k;
scanf("%d%d",&op,&s);
if(op==1)
printf("%d\n",ask(++s));
else
{
scanf("%d",&k);
change(++s,k);
}
}
return 0;
}
P4135 作诗
题意:查询区间内出现偶数次的数
此时每个块的贡献不是独立的,单独考虑每个块不好搞
如果拿一个桶维护每个数出现的次数,即可增量维护好数的个数
设
设
查询时,先取出
令
code
#include<bits/stdc++.h>
using namespace std;
const int N=100010,BB=410;
int n,c,m,a[N];
int T[N],cnt[N][BB],s[BB][BB];
int B,t,L[BB],R[BB],pos[N];
void prework()
{
B=sqrt(n); t=n/B;
for(int i=1; i<=t; i++)
L[i]=(i-1)*B+1,R[i]=i*B;
if(R[t]<n)
t++,L[t]=R[t-1]+1,R[t]=n;
for(int i=1; i<=t; i++)
for(int j=L[i]; j<=R[i]; j++)
pos[j]=i;
for(int i=1; i<=t; i++)
{
for(int j=i; j<=t; j++)
{
int tmp=s[i][j-1];
for(int k=L[j]; k<=R[j]; k++)
{
T[a[k]]++;
if(T[a[k]]&1 && T[a[k]]!=1)
tmp--;
else if(T[a[k]]%2==0)
tmp++;
}
s[i][j]=tmp;
}
for(int j=L[i]; j<=n; j++)
T[a[j]]--;
}
for(int i=1; i<=t; i++)
{
for(int j=1; j<=c; j++)
cnt[j][i]=cnt[j][i-1];
for(int j=L[i]; j<=R[i]; j++)
cnt[a[j]][i]++;
}
}
int ask(int l,int r)
{
int p=pos[l],q=pos[r];
if(p==q)
{
int res=0;
for(int i=l; i<=r; i++)
{
T[a[i]]++;
if(T[a[i]]%2==0)
res++;
else if(T[a[i]]!=1)
res--;
}
for(int i=l; i<=r; i++)
T[a[i]]--;
return res;
}
int res=s[p+1][q-1];
for(int i=l; i<=R[p]; i++)
{
T[a[i]]++;
if((T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p])%2==0)
res++;
else if(T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p]!=1)
res--;
}
for(int i=L[q]; i<=r; i++)
{
T[a[i]]++;
if((T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p])%2==0)
res++;
else if(T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p]!=1)
res--;
}
for(int i=l; i<=R[p]; i++)
T[a[i]]--;
for(int i=L[q]; i<=r; i++)
T[a[i]]--;
return res;
}
int main()
{
scanf("%d%d%d",&n,&c,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
prework();
int last=0;
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
l=(l+last)%n+1; r=(r+last)%n+1;
if(l>r)
swap(l,r);
last=ask(l,r);
printf("%d\n",last);
}
return 0;
}
P4168 [Violet] 蒲公英
题意:求区间众数,强制在线
同上题一样的操作,将
code
#include<bits/stdc++.h>
using namespace std;
const int N=40010,BB=210;
int n,m,a[N],b[N],rk[N];
int T[N],cnt[N][BB],s[BB][BB];
int B,t,L[BB],R[BB],pos[N];
void prework()
{
B=sqrt(n); t=n/B;
for(int i=1; i<=t; i++)
L[i]=(i-1)*B+1,R[i]=i*B;
if(R[t]<n)
t++,L[t]=R[t-1]+1,R[t]=n;
for(int i=1; i<=t; i++)
for(int j=L[i]; j<=R[i]; j++)
pos[j]=i;
for(int i=1; i<=t; i++)
{
for(int j=i; j<=t; j++)
{
s[i][j]=s[i][j-1];
for(int k=L[j]; k<=R[j]; k++)
{
T[a[k]]++;
if(T[a[k]]==T[s[i][j]] && a[k]<s[i][j])
s[i][j]=a[k];
else if(T[a[k]]>T[s[i][j]])
s[i][j]=a[k];
}
}
for(int j=L[i]; j<=n; j++)
T[a[j]]--;
}
for(int i=1; i<=t; i++)
{
for(int j=1; j<=n; j++)
cnt[j][i]=cnt[j][i-1];
for(int j=L[i]; j<=R[i]; j++)
cnt[a[j]][i]++;
}
}
int ask(int l,int r)
{
int p=pos[l],q=pos[r],mx=0;
if(p==q)
{
for(int i=l; i<=r; i++)
{
T[a[i]]++;
if(T[a[i]]==T[mx] && a[i]<mx)
mx=a[i];
else if(T[a[i]]>T[mx])
mx=a[i];
}
for(int i=l; i<=r; i++)
T[a[i]]--;
return mx;
}
mx=s[p+1][q-1];
for(int i=l; i<=R[p]; i++)
{
T[a[i]]++;
if(T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p]==T[mx]+cnt[mx][q-1]-cnt[mx][p] && a[i]<mx)
mx=a[i];
else if(T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p]>T[mx]+cnt[mx][q-1]-cnt[mx][p])
mx=a[i];
}
for(int i=L[q]; i<=r; i++)
{
T[a[i]]++;
if(T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p]==T[mx]+cnt[mx][q-1]-cnt[mx][p] && a[i]<mx)
mx=a[i];
else if(T[a[i]]+cnt[a[i]][q-1]-cnt[a[i]][p]>T[mx]+cnt[mx][q-1]-cnt[mx][p])
mx=a[i];
}
for(int i=l; i<=R[p]; i++)
T[a[i]]--;
for(int i=L[q]; i<=r; i++)
T[a[i]]--;
return mx;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]),rk[i]=a[i];
sort(rk+1,rk+1+n);
int nn=unique(rk+1,rk+1+n)-(rk+1);
for(int i=1; i<=n; i++)
{
int x=lower_bound(rk+1,rk+1+nn,a[i])-rk;
b[x]=a[i]; a[i]=x;
}
prework();
int last=0;
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
l=(l+last-1)%n+1; r=(r+last-1)%n+1;
if(l>r)
swap(l,r);
last=b[ask(l,r)];
printf("%d\n",last);
}
return 0;
}
P5048 [Ynoi2019 模拟赛] Yuno loves sqrt technology III
题意:求区间众数出现的次数,要求空间
将上题的
空间的瓶颈在于
我们可以拿个 tmx++
即可
这样暴力加的操作次数最多为
code
#include<bits/stdc++.h>
using namespace std;
const int N=500010,BB=810;
int n,m,a[N],rk[N],id[N];
int T[N],s[BB][BB];
int B,t,L[BB],R[BB],pos[N];
vector <int> cnt[N];
void prework()
{
B=sqrt(n); t=n/B;
for(int i=1; i<=t; i++)
L[i]=(i-1)*B+1,R[i]=i*B;
if(R[t]<n)
t++,L[t]=R[t-1]+1,R[t]=n;
for(int i=1; i<=t; i++)
for(int j=L[i]; j<=R[i]; j++)
pos[j]=i;
for(int i=1; i<=t; i++)
{
for(int j=i; j<=t; j++)
{
s[i][j]=s[i][j-1];
for(int k=L[j]; k<=R[j]; k++)
{
T[a[k]]++;
if(T[a[k]]>=s[i][j])
s[i][j]=T[a[k]];
}
}
for(int j=L[i]; j<=n; j++)
T[a[j]]--;
}
for(int i=1; i<=n; i++)
cnt[a[i]].push_back(i),id[i]=cnt[a[i]].size()-1;
}
int ask(int l,int r)
{
int p=pos[l],q=pos[r],mx=0,tmx=0;
if(p==q)
{
for(int i=l; i<=r; i++)
{
T[a[i]]++;
if(T[a[i]]>=tmx)
tmx=T[a[i]];
}
for(int i=l; i<=r; i++)
T[a[i]]--;
return tmx;
}
tmx=s[p+1][q-1];
for(int i=l; i<=R[p]; i++)
while(id[i]+tmx<cnt[a[i]].size() && cnt[a[i]][id[i]+tmx]<=r)
tmx++;
for(int i=L[q]; i<=r; i++)
while(id[i]-tmx>=0 && cnt[a[i]][id[i]-tmx]>=l)
tmx++;
return tmx;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]),rk[i]=a[i];
sort(rk+1,rk+1+n);
int nn=unique(rk+1,rk+1+n)-(rk+1);
for(int i=1; i<=n; i++)
a[i]=lower_bound(rk+1,rk+1+nn,a[i])-rk;
prework();
int last=0;
while(m--)
{
int l,r;
scanf("%d%d",&l,&r);
l^=last; r^=last;
if(l>r)
swap(l,r);
last=ask(l,r);
printf("%d\n",last);
}
return 0;
}
P5046 [Ynoi2019 模拟赛] Yuno loves sqrt technology I
题意:求区间逆序对数,强制在线
无语了
code
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=100010,BB=410;
int n,m,a[N];
int pre[N],suf[N],cnt[N][BB],tmp[BB][BB],tmpp[2][BB];
LL s[BB][BB];
int B,t,L[BB],R[BB],pos[N];
struct BIT
{
int c[N];
void add(int x,int y)
{
for(x; x<=n; x+=(x&-x))
c[x]+=y;
}
int query(int x)
{
int res=0;
for(x; x; x-=(x&-x))
res+=c[x];
return res;
}
}tree;
int msort1(int l,int r)
{
int res=0,i=1,j=1;
while(i<=B && j<=B)
{
if(tmp[l][i]<tmp[r][j])
i++;
else
res+=B-i+1,j++;
}
return res;
}
int msort2()
{
int res=0,i=1,j=1;
while(i<=tmpp[0][0] && j<=tmpp[1][0])
{
if(tmpp[0][i]<tmpp[1][j])
i++;
else
res+=tmpp[0][0]-i+1,j++;
}
return res;
}
int calc(int l,int r,int flag)
{
if(!flag)
return msort1(l,r);
else
return msort2();
}
void prework()
{
B=sqrt(n); t=n/B;
for(int i=1; i<=t; i++)
L[i]=(i-1)*B+1,R[i]=i*B;
if(R[t]<n)
t++,L[t]=R[t-1]+1,R[t]=n;
for(int i=1; i<=t; i++)
for(int j=L[i]; j<=R[i]; j++)
pos[j]=i;
for(int i=1; i<=t; i++)
{
for(int j=L[i]; j<=R[i]; j++)
{
if(j!=L[i])
pre[j]=pre[j-1];
pre[j]+=j-L[i]-tree.query(a[j]);
tree.add(a[j],1);
}
for(int j=L[i]; j<=R[i]; j++)
tree.add(a[j],-1);
for(int j=R[i]; j>=L[i]; j--)
{
suf[j]+=suf[j+1]+tree.query(a[j]);
tree.add(a[j],1);
}
for(int j=R[i]; j>=L[i]; j--)
tree.add(a[j],-1);
// cout<<i<<"\n";
// for(int j=L[i]; j<=R[i]; j++)
// cout<<j<<":"<<pre[j]<<" "<<suf[j]<<endl;
}
for(int i=1; i<=t; i++)
{
for(int j=L[i]; j<=R[i]; j++)
cnt[a[j]][i]++;
}
for(int i=1; i<=t; i++)
{
for(int j=1; j<=n; j++)
cnt[j][i]+=cnt[j-1][i];
for(int j=1; j<=n; j++)
cnt[j][i]+=cnt[j][i-1];
}
for(int i=1; i<=t; i++)
{
for(int j=L[i]; j<=R[i]; j++)
tmp[i][++tmp[i][0]]=a[j];
sort(tmp[i]+1,tmp[i]+1+B);
}
for(int i=1; i<=t; i++)
s[i][i]=pre[R[i]];//,cout<<i<<" "<<s[i][i]<<endl;
for(int len=2; len<=t; len++)
{
for(int i=1; i+len-1<=t; i++)
{
int j=i+len-1;
s[i][j]=s[i+1][j]+s[i][j-1]-s[i+1][j-1]+(LL)calc(i,j,0);
// cout<<i<<" "<<j<<" : "<<s[i][j]<<" "<<calc(i,j,0)<<endl;
}
}
}
LL ask(int l,int r)
{
int p=pos[l],q=pos[r];
if(p==q)
{
LL res=0;
for(int i=r; i>=l; i--)
{
res+=(LL)tree.query(a[i]);
tree.add(a[i],1);
}
for(int i=l; i<=r; i++)
tree.add(a[i],-1);
return res;
}
// return 0;
LL res=s[p+1][q-1]+suf[l]+pre[r];
// cout<<s[p+1][q-1]<<" "<<suf[l]<<" "<<pre[r]<<endl;
tmpp[0][0]=tmpp[1][0]=0;
for(int i=l; i<=R[p]; i++)
{
int tmp=cnt[a[i]][q-1]-cnt[a[i]][p];
res+=(LL)tmp;
tmpp[0][++tmpp[0][0]]=a[i];
}
// cout<<res<<endl;
for(int i=L[q]; i<=r; i++)
{
int tmp=cnt[a[i]][q-1]-cnt[a[i]][p];
// cout<<"kkk"<<a[i]<<" "<<tmp<<endl;
res+=1LL*((q-p-1)*B-tmp);
tmpp[1][++tmpp[1][0]]=a[i];
}
sort(tmpp[0]+1,tmpp[0]+1+R[p]-l+1);
sort(tmpp[1]+1,tmpp[1]+1+r-L[q]+1);
// cout<<res<<endl<<tmpp[0][1]<<" "<<tmpp[1][1]<<" "<<tmpp[1][2]<<endl;
res+=(LL)calc(0,1,1);
return res;
}
signed main()
{
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
prework();
LL last=0;
for(int i=1; i<=m; i++)
{
int l,r;
scanf("%d%d",&l,&r);
l^=last; r^=last;
if(l>r)
swap(l,r);
// cout<<l<<" "<<r<<endl;
last=ask(l,r);
printf("%lld\n",last);
}
return 0;
}
P3396 哈希冲突
题意:给定长度为
的序列 ,要求支持:
- 单点修改
- 查询
根号分治入门题
根号复杂度会产生于一些非常自然的问题中
当
对于
code
#include<bits/stdc++.h>
using namespace std;
const int N=150010,BB=410;
int n,m,B,a[N];
int ans[BB][BB];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
B=sqrt(n);
for(int i=1; i<=n; i++)
for(int j=1; j<B; j++)
ans[j][i%j]+=a[i];
while(m--)
{
char op[2]; int x,y;
scanf("%s%d%d",op,&x,&y);
if(op[0]=='A')
{
if(x>=B)
{
int res=0;
for(int i=y; i<=n; i+=x)
res+=a[i];
printf("%d\n",res);
}
else
printf("%d\n",ans[x][y]);
}
else
{
for(int i=1; i<B; i++)
ans[i][x%i]+=y-a[x];
a[x]=y;
}
}
return 0;
}
P5309 [Ynoi2011] 初始化
题意:给定长度为
的序列,要求支持
- 对所有
等于 的数加 - 求区间
的和
由于跳着加,首先考虑根号分治。
当
当
注意卡常,开 long long
最后再取模
code
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=200010,BB=500;
const int MOD=1e9+7;
int n,m;
int B,t,L[BB],R[BB],pos[N];
LL a[N],s[BB],sum[BB][BB];
void prework()
{
B=sqrt(n); t=n/B;
for(int i=1; i<=t; i++)
L[i]=(i-1)*B+1,R[i]=i*B;
if(R[t]<n)
t++,L[t]=R[t-1]+1,R[t]=n;
for(int i=1; i<=t; i++)
for(int j=L[i]; j<=R[i]; j++)
pos[j]=i;
for(int i=1; i<=t; i++)
for(int j=L[i]; j<=R[i]; j++)
s[i]+=a[j];
}
LL ask(int l,int r)
{
int p=pos[l],q=pos[r]; LL res=0;
if(p==q)
{
for(int i=l; i<=r; i++)
res+=a[i];
return res;
}
for(int i=p+1; i<=q-1; i++)
res+=s[i];
for(int i=l; i<=R[p]; i++)
res+=a[i];
for(int i=L[q]; i<=r; i++)
res+=a[i];
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++)
scanf("%lld",&a[i]);
prework();
while(m--)
{
int op,x,y,z,l,r;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d%d",&x,&y,&z); y%=x;
if(x>B)
for(int i=y; i<=n; i+=x)
a[i]+=z,s[pos[i]]+=z;
else
for(int i=y; i<x; i++)
sum[x][i]+=z;
}
else
{
scanf("%d%d",&l,&r);
LL res=ask(l,r);
for(int i=1; i<=B; i++)
{
res+=1LL*sum[i][i-1]*(r/i-l/i);
res+=sum[i][r%i]-(l%i? sum[i][l%i-1]:0);
}
printf("%lld\n",res%MOD);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?