优雅的优化
分块
分块即为将整个序列分为多个块来处理区间信息,常的操作需支持修改和查询。
一个区间,它一定由一些完整的块和剩余的单点。对于完整的块,我们直接对整个块一起做修改和查询;对于剩余的单点,我们直接暴力修改。
通常块长被分为
代码模板:
int n, a[N]; //原数组
int p, pos[N]; //块长 和 每个点属于的块编号
int m, l[N], r[N]; //块的数量 和 每个块的左右端点
int b[N], k[N]; //查询用数组 和 记录块修改的数组
inline void work(){ //预处理
p = sqrt(n);
m = ceil(1.0 * n / p); //计算块数
for(int i = 1; i <= m; ++ i){
l[i] = r[i - 1] + 1;
r[i] = i * p; //计算块左右端点
for(int j = l[i]; j <= r[i]; ++ j){
pos[j] = i; //记录当前点块编号
b[i] = a[i]; //看题目要求
}
}
}
inline void add(int x, int y){ //修改区间[x, y]
for(int i = x; i <= min(y, r[pos[x]]); ++ i){ //左剩余区间
a[i] + ? //看题目要求
}
if(pos[x] != pos[y]){ //左右剩余不重
for(int i = max(l[pos[y]], x); i <= y; ++ i){ //右剩余区间
a[i] + ? //同上
}
}
for(int i = pos[x] + 1; i <= pos[y] - 1; ++ i){ //整块修改
k[i] + ?//同上
}
}
inline int ask(int x, int y){ //查询区间
int sum = 0;
for(int i = x; i <= min(y, r[pos[x]]); ++ i){ //左剩余区间
sum += a[i]? //看题目要求
}
if(pos[x] != pos[y]){ //左右剩余不重
for(int i = max(l[pos[y]], x); i <= y; ++ i){ //右剩余区间
sum += a[i]? //同上
}
}
for(int i = pos[x] + 1; i <= pos[y] - 1; ++ i){ //整块修改
sum += k[i]? //同上
}
return sum;
}
通常使用分块算法的数据范围为
st表
以
主体是运用倍增的思想,
求st表我们还需要一个
具体理解看代码吧
int lg[N];
int st[N][22];
inline int ask(int l, int r){
int k = lg[r - l + 1];
return max(st[l][k], st[r - (1 << k) + 1][k]);
// 查询区间最大值
}
int main(){
for(int i = 1; i <= n; ++ i){
st[i][0] = a[i];
}
for(int i = 2; i <= n; ++ i){
lg[i] = lg[i >> 1] + 1;
}
for(int i = 1; i <= lg[n]; ++ i){
for(int j = 1; j + (1 << i) - 1 <= n; ++ j){
st[j][i] = max(st[j][i - 1], st[j + (1 << (i - 1))][i - 1]);
// 此处为求区间最大值
}
}
}
st表求LCA
CSDN - st表求LCA
众所周知,dfs序……算了,我不会讲,看代码
int dfn[N << 1], cnt, d[N];
//d 用来存每个节点第一次出现的位置
int lg[N << 1], st[N << 1][20];
// st 表维护区间深度最小值
inline void Dfs(int now, int fath){
dfn[++ cnt] = now;
st[cnt][0] = now;
d[now] = cnt;
for(int i = head[now]; i; i = e[i].nxt){
int v = e[i].to;
if(v != fath){
Dfs(v, now);
dfn[++ cnt] = now;
st[cnt][0] = now;
}
}
return ;
}
inline int Lca(int x, int y){
if(x > y) swap(x, y);
int k = lg[y - x + 1];
if(dep[st[x][k]] < dep[st[y - (1 << k) + 1][k]]){
return st[x][k];
}
else{
return st[y - (1 << k) + 1][k];
}
}
int main(){
Dfs(1, 0);
for(int i = 2; i <= cnt; ++ i){
lg[i] = lg[i >> 1] + 1;
}
//这样处理 st表 查询时可以直接返回节点编号
for(int i = 1; i <= lg[cnt]; ++ i){
for(int j = 1; j + (1 << i) - 1 <= cnt; ++ j){
if(dep[st[j][i - 1]] < dep[st[j + (1 << (i - 1))][i - 1]]){
st[j][i] = st[j][i - 1];
}
else{
st[j][i] = st[j + (1 << (i - 1))][i - 1];
}
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】