题解:CF896E&P4117

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;
}
posted @ 2025-06-04 19:36  FugiPig  阅读(20)  评论(0)    收藏  举报