关于根号分治

根号分治就是暴力+暴力!——recloud

定义

根号分治是一种写题的trick(技巧),只是一种思想,以例题来作讲解

1.CF1207F

image

区间查询,单点修改。

很容易有两种很直接的暴力思路:

  • 单点直接暴力修改:\(O(1)\)+区间暴力查询\(O( \dfrac{5e5}{x} )\)
    当x每次为1,总体时间可达\(O(5e5*n)=O(n^2)\)

  • 修改时维护一个\(ans[i][j],\)表示取模\(x\)\(y\)的总值,每次暴力遍历x,当x为n时,可达\(O(x)=O(n)\)
    查询时直接ans输出,\(O(1)\),总体时间为\(O(n^2)\).

欸,两个\(n^2\)image

观察一下:,第一个式子的难点在于\(O( \dfrac{5e5}{x} )\),当x过小,查询过复杂

第二个式子在于修改时\(O(x)\)x太大修改太复杂,结合一下?

我们预订一个阈值\(b\),\(x\)大于\(b\)时,使用方案一,否则使用方案二

代码如下,本题阈值为700:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int M=5e5+110,N=1e3+110;
inline int read(){
	int sum=0,k=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')k=-1;c=getchar();
	}while(c>='0'&&c<='9'){sum=sum*10+c-48;c=getchar();
	}return sum*k;
}
inline void wr(int x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) wr(x/10);
	putchar(x%10+'0');
}
inline void co(int x){
	wr(x);putchar('\n');
}
int q=0,ans=0;
int a[M],res[N][N];

signed main(){
	q=read();
	while(q--){
		int opt=read(),x=read(),y=read();
		if(opt==1){
			for(int i=1;i<700;i++) res[i][x%i]+=y;
			a[x]+=y;
		}else{
			if(x<700) co(res[x][y]);
			else{
				for(int i=y;i<=M-110;i+=x) ans+=a[i];
				co(ans);ans=0;	
			} 
		}
	}
	return 0;
}

至于为什么阈值为700?

额,根号分治,5e5=500000的范围,\(\sqrt{500000}=707.1067811865476,\)而且:

image

posted @ 2025-06-25 21:05  rerecloud  阅读(65)  评论(1)    收藏  举报