树状数组

前言

树状数组用来维护单点修改与区间查询。
维护的内容满足结合律可查分
树状数组通常与差分前缀和一起使用。
同时满足二分结构。

实现

对于一个二进制数 \(x\) 维护 \(x-lowbit(x)+1\)\(x\) 的信息。

模板
void modify(int x,int c){for(;x<=n;x+=x&-x)t[x]+=c;}
int query(int x){int ans=0;for(;x;x-=x&-x)ans+=t[x]; return ans;}
例题

[省选联考 2020 A/B 卷] 冰火战士
[HEOI2012] 采花
[SDOI2009] 虔诚的墓主人

区间修改&区间查询

考虑树状数组的性质。
将区间修改以差分形式改为单点修改。
区间求和以区间加为例:

\[{\sum_{i=1}^{n}} {\sum_{j=1}^{i}} {d_j} = {\sum_{i=1}^{n}} {d_i}*(n-i+1) = (n + 1) * {\sum_{i=1}^{n}} {d_i} - {\sum_{i=1}^{n}} {d_i}*i \]

维护 \(d_i\)\(d_i * i\) 即可。
模板

权值树状数组

【模板】普通平衡树 为例。
相对于普通树状数组。
权值树状数组可以查询第第 \(k\) 大的数。
考虑树状数组本质类似倍增。
从大到小查询即可。

代码
int kth(int k){
	int w=0;
	for(int i=22;i>=0;i--){
		if(w+(1<<i)>top||k-t[w+(1<<i)]<=0)continue;
		w+=(1<<i); k-=t[w];
	}
	return w+1;
}
例题

[NOI Online #1 提高组] 冒泡排序
[POI2015] LOG
[TJOI2017] 异或和

树状数组维护不可差分信息

单点修改 区间最值 为例。
树状数组不改变维护内容。
考虑查询中 \(x-lowbit+1 < l\) 的情况。
\(x\) 单独计入贡献。
递归处理 \(val(l,x-1)\)
易得时间复杂度为 \(O(log^{2}n)\)

代码
int query(int l,int r){
	int ans=0;
	while(r>=l){
		ans=max(ans,a[r]); r--;
		for(;r-(r&-r)>=l;r-=r&-r)
			ans=max(ans,t[r]);
//		循环条件不能写成 r - lowbit(r) + 1 >= l
//		否则 l = 1 时,r 跳到 0 会死循环
	}
	return ans;
}
posted @ 2024-12-18 14:03  C_Wish  阅读(39)  评论(0)    收藏  举报