题解:CF896E&P4117
考虑分块,对每个块建立一个桶,这样将 \(a_i\) 减去 \(x\) 也就是将 \(a_i\) 所在的等价类(桶)和 \(a_i-x\) 对应的等价类合并,可以用并查集维护。
但这样的复杂度是 \(O(\sum >x的数的个数)\) 的,无法接受。发现每个块的最大值单调不增,这启发我们要使每次的枚举量和最大值的减小量相等。
令当前最大值为 \(m\),我们可以按照 \(2x\) 和 \(m\) 的大小关系来讨论:
-
\(2x\ge m\),此时直接枚举 \((x,m]\) 即可,因为新的 \(m\) 一定会 \(\le x\)。因此按 \(2x\) 来分类就是因为 \(m>2x\) 使新的 \(m\) 仍会 \(>x\),进而导致最大值的减小量并不是枚举量 \(m-x\)。
-
\(2x<m\),此时 \(m\) 的减小量为 \(x\),我们也就要使枚举量为 \(x\),因此我们可以将 \([1,x]\) 内的数用并查集加上 \(x\),再通过打标记给整个块减 \(x\) 即可。
这样每个块的复杂度即为 \(O(V)\),总复杂度即为 \(O(\sqrt n(q+V))\),空间复杂度为 \(O(V\sqrt n)\)。对于加强版(P4117),需要将询问离线下来,对每个块依次处理所有的操作,这样空间复杂度就降低到了 \(O(V)\)。
参考资料:第二分块 学习笔记,题解 CF896E 【Welcome home, Chtholly】
Code of CF896E:
#include<iostream>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxn=1e5+5,B=333;
int a1[maxn],fa[maxn],rt[B+10][maxn<<1],bel[maxn],aw[maxn],siz[maxn],col[B+10],mx[B+10],L[B+10],R[B+10];
inline int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void merge(int &x,int &y,int w){
if(!x){
x=int(y);
aw[x]=w;
y=0;
return;
}
if(!y)return;
if(siz[x]<siz[y]){
int tx=x,ty=y;
y=tx;
x=ty;
}
fa[y]=x;
siz[x]+=siz[y];
aw[x]=w;
y=0;
}
inline void build(int x){
int l=L[x],r=R[x];
mx[x]=col[x]=0;
rep(v1,l,r){
fa[v1]=v1;
siz[v1]=1;
mx[x]=max(mx[x],aw[v1]=a1[v1]);
int t=v1;
merge(rt[x][a1[v1]],t,a1[v1]);
}
}
inline void update(int x){
int l=L[x],r=R[x];
rep(v1,l,r){
rt[x][aw[find(v1)]]=0;
a1[v1]=aw[find(v1)]-col[x];
}
}
int main()
{
int in,im;
cin>>in>>im;
rep(v1,1,in){
scanf("%d",a1+v1);
bel[v1]=(v1-1)/B+1;
if(!L[bel[v1]])L[bel[v1]]=v1;
R[bel[v1]]=v1;
}
rep(v1,1,bel[in])build(v1);
while(im--){
int iop,il,ir,ix;
scanf("%d %d %d %d",&iop,&il,&ir,&ix);
if(iop==1){
if(bel[il]==bel[ir]){
update(bel[il]);
rep(v1,il,ir)if(a1[v1]>ix)a1[v1]-=ix;
build(bel[il]);
}
else{
update(bel[il]);
rep(v1,il,R[bel[il]])if(a1[v1]>ix)a1[v1]-=ix;
build(bel[il]);
rep(v1,bel[il]+1,bel[ir]-1){
if(mx[v1]<=ix*2){
rep(v2,ix+col[v1]+1,mx[v1]+col[v1])if(rt[v1][v2])merge(rt[v1][v2-ix],rt[v1][v2],v2-ix);
if(mx[v1]>ix)mx[v1]=max(mx[v1]-ix,ix);
}
else{
per(v2,ix+col[v1],col[v1]+1)if(rt[v1][v2])merge(rt[v1][v2+ix],rt[v1][v2],v2+ix);
mx[v1]=max(mx[v1]-ix,ix);
col[v1]+=ix;
}
}
update(bel[ir]);
rep(v1,L[bel[ir]],ir)if(a1[v1]>ix)a1[v1]-=ix;
build(bel[ir]);
}
}
else{
int ans=0;
if(bel[il]==bel[ir]){
rep(v1,il,ir)if(aw[find(v1)]-col[bel[il]]==ix)ans++;
}
else{
rep(v1,il,R[bel[il]])if(aw[find(v1)]-col[bel[il]]==ix)ans++;
rep(v1,bel[il]+1,bel[ir]-1)ans+=siz[rt[v1][ix+col[v1]]];
rep(v1,L[bel[ir]],ir)if(aw[find(v1)]-col[bel[ir]]==ix)ans++;
}
printf("%d\n",ans);
}
}
return 0;
}
P4117:
#include<iostream>
#define rep(i,l,r) for(int i=(l);i<=(r);i++)
#define per(i,l,r) for(int i=(l);i>=(r);i--)
using namespace std;
const int maxn=1e6+5,maxm=5e5+5,maxv=4e5+10,B=1e3,V=4e5+5;
int a1[maxn],fa[B+10],rt[maxv],aw[B+10],siz[B+10];
int ans[maxm],op[maxm],al[maxm],ar[maxm],ax[maxm],col,mx;
inline void merge(int x,int y){
if(!rt[x]){
rt[x]=rt[y];
rt[y]=0;
aw[rt[x]]=x;
return;
}
if(!rt[y])return;
if(siz[rt[x]]<siz[rt[y]])swap(rt[x],rt[y]);
siz[rt[x]]+=siz[rt[y]];
fa[rt[y]]=rt[x];
aw[rt[x]]=x;
rt[y]=0;
}
inline void build(int l,int r){
col=mx=0;
rep(v1,l,r){
rt[V]=fa[v1]=v1;
siz[v1]=1;
mx=max(mx,a1[v1]);
merge(a1[v1],V);
}
}
inline int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);
}
inline void goback(int l,int r){
rep(v1,l,r){
a1[v1]=aw[find(v1)]-col;
rt[aw[find(v1)]]=0;
}
}
int main()
{
int in,im;
cin>>in>>im;
rep(v1,1,in){
scanf("%d",a1+v1);
}
int qcnt=0;
rep(v1,1,im){
scanf("%d %d %d %d",op+v1,al+v1,ar+v1,ax+v1);
if(op[v1]==2)op[v1]=++qcnt;
else op[v1]=-1;
}
rep(v1,1,in){
int l=1,r=min(B,in-v1+1);
rep(v2,l,r)a1[v2]=a1[v2+v1-1];
build(l,r);
rep(v2,1,im){
al[v2]-=v1-1;
ar[v2]-=v1-1;
if(~op[v2]){
if(al[v2]<=l&&ar[v2]>=r){
ans[op[v2]]+=siz[rt[ax[v2]+col]];
al[v2]+=v1-1;
ar[v2]+=v1-1;
continue;
}
int cl=max(l,al[v2]),cr=min(r,ar[v2]);
if(cl>r||cr<l){
al[v2]+=v1-1;
ar[v2]+=v1-1;
continue;
}
rep(v3,cl,cr)if(aw[find(v3)]-col==ax[v2])ans[op[v2]]++;
}
else{
if(al[v2]<=l&&ar[v2]>=r){
if(mx<=ax[v2]*2){
rep(v3,ax[v2]+1,mx){
if(rt[v3+col])merge(v3-ax[v2]+col,v3+col);
}
if(mx>ax[v2])mx=max(ax[v2],mx-ax[v2]);
}
else{
per(v3,ax[v2],0)if(rt[v3+col])merge(v3+ax[v2]+col,v3+col);
col+=ax[v2];
mx=max(ax[v2],mx-ax[v2]);
}
al[v2]+=v1-1;
ar[v2]+=v1-1;
continue;
}
int cl=max(l,al[v2]),cr=min(r,ar[v2]);
if(cl>r||cr<l){
al[v2]+=v1-1;
ar[v2]+=v1-1;
continue;
}
goback(l,r);
rep(v3,cl,cr)if(a1[v3]>ax[v2])a1[v3]-=ax[v2];
build(l,r);
}
al[v2]+=v1-1;
ar[v2]+=v1-1;
}
goback(l,r);
v1=r+v1-1;
}
rep(v1,1,qcnt)printf("%d\n",ans[v1]);
return 0;
}

浙公网安备 33010602011771号