标签:数据 树状数组 改变 一段 树状 时间复杂度 nbsp style 下标
分块与树状数组均在区间问题上有重要的应用
emm分块效率上不如树状数组,但是思路比较好想
先说分块:
将n个数的序列分为sqrt(n)块,预处理每块数据的信息以加快后续对区间信息的查询
先上一段代码:
const int maxn = 5e5 + 50; int sum[maxn],a[maxn],l[maxn],r[maxn],belong[maxn]; int block,num; void build(){ block = sqrt(n); num = n/block; if(n%block) num++; for(int i = 1; i <= num; i++) l[i] = (i-1)*block+1, r[i] = i*block; r[num] = n; for(int i = 1; i <= num; i++){ for(int j = l[i]; j <= r[i]; j++) belong[j] = i, sum[i] += a[j]; } }
代码中的全局变量有这些是需要预处理的:sum[i]表示第i块数据的和(也可是异或和、乘积这类,一样的)
a[i]为第i个数据,l[i],r[i]分别为第i块的左右端点下标,belong[i]存储第i个数所属的分块
预处理过后,贴上单点修改/更新和区间查询的代码:
inline void update(int x, int y){ a[x] += y; sum[belong[x]] += y; } inline int query(int x, int y){ int ans = 0; if(belong[x] == belong[y]){ for(int i = x; i <= y; i++) ans += a[i]; return ans; } for(int i = x; i <= r[belong[x]]; i++) ans += a[i]; for(int i = belong[x] + 1; i < belong[y]; i++) ans += sum[i]; for(int i = l[belong[y]]; i <= y; i++) ans += a[i]; return ans; }
其中对单点进行数据更新只需将数组a中数据改变,再将下标为x所属的块的总和增加y即可
而查询区间[x,y]的和,分块这里采用的是暴力求和
1.当x,y在同一块中时,遍历求和
2.当x,y不在同一块,遍历求和x到x所属块的右边界,再加上sum[x+1]到sum[y-1],再遍历求和y所属块的左边界到y
时间复杂度均为O(sqrt(n)) 单点修改为O(1)
qwq先写到这,树状数组明天再总结再写
标签:数据 树状数组 改变 一段 树状 时间复杂度 nbsp style 下标
原文地址:https://www.cnblogs.com/leafsblogowo/p/12668906.html