树状数组笔记

特点:lowbit(x)=最低含 1 位的二进制权值 =tree[x]的维护的长度

           tree[x]保存以x为根的子树中叶节点值的和

           tree[x]的父节点为tree[x+lowbit(x)]

 

点单修改&区间查询

add操作,即单点修改:

 query操作,即查询前缀和:

 ask操作,即查询区间和:
两个前缀和相减。

代码:

#include<iostream>
#define lowbit(x) (x & -x) // lowbit运算
using namespace std;

int tree[25],a[25], n;

//在第idx位置加上k
void add(int idx, int k) {
	for (; idx <= n; idx += lowbit(idx)) {
		tree[idx] += k;
	}
}

//查询第idx位置的前缀和
int query(int idx) {
	int ans = 0;
	for (; idx >= 1; idx -= lowbit(idx)) {
		ans += tree[idx];
	}
	return ans;
}

//查询区间[l, r]的和
int ask(int l, int r) {
	return query(r) - query(l - 1);
}

int main(){
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		add(i, a[i]);
	}
	return 0;
}

 

区间修改&单点查询

用树状数组tree[]维护一个增量数组(利用了差分数组的原理),当要在[x, y]区间加上k时,只需要在差分数组x处加k,在y处减k,则query(x)得到是原数组a[]在x处的增量(差分数组在x处的前缀和为数组在x处元素值——>增量数组在x处的前缀和为数组在x处的增量)。

注意:最后单点查询输出的是原数组元素值a[x]加上增量值tree[x](a[x] + tree[x])。

代码:

#include<iostream>
#define lowbit(x) (x & -x) // lowbit运算
using namespace std;

int tree[25],a[25], n, q;

//在第idx位置加上k
void add(int idx, int k) {
	for (; idx <= n; idx += lowbit(idx)) {
		tree[idx] += k;
	}
}

//查询第idx位置的前缀和
int query(int idx) {
	int ans = 0;
	for (; idx >= 1; idx -= lowbit(idx)) {
		ans += tree[idx];
	}
	return ans;
}


int main(){
	cin >> n >> q;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= q; i++) {
		int op, x, y, k;
		cin >> op;
		if (op == 1) {
			cin >> x >> y >> k;
			add(x, k);
			add(y + 1, -k);
		}
		if (op == 2) {
			cin >> x;
			cout << a[x] + query(x) << endl;
		}
	}
	return 0;
}

1、树状数组处理逆序对问题

逆序对 - 洛谷

树状数据相当于桶,数列中每出现一个数其对应位置的桶内元素+1,则该树状数组的前缀和query(x)为x和比x小的数在数列中的出现次数。我们逐一将数列中的数放进树状数组这个桶里,当处理到数列中第i个数时,其对应的逆序对个数为i - query(i)。

逆序对——>统计比x大的数的个数——>排序后用桶来统计——>要统计的个数对应的桶是连续的——>区间和——>树状数组。

2、逆序对在排序中的应用

P1966 [NOIP2013 提高组] 火柴排队 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

将数组A和数组B中元素相同的位置排序相同

方法:c[B[i].x]=A[i].x

 A:2 3 1 4->1 2 3 4对应原编号为:3 1 2 4
 B:3 2 1 4->1 2 3 4对应原编号为:3 2 1 4
 c[B[1]编号]=c[3]=a[1]编号=3
 c[B[2]编号]=c[2]=a[2]编号=1
 c[B[3]编号]=c[1]=a[3]编号=2
 c[B[4]编号]=c[4]=a[4]编号=4
 于是c[1]=2 c[2]=1 c[3]=3 c[4]=4
 逆序对数=1,交换一次,结束;

为什么上述操作可以实现?因为产生了逆序;只要序列原来对应的数是符合要求的,他们编号相同,那么我们排完序两数的相对位置不发生改变,因此不会产生逆序;一旦A中编号与B中的不同,c数组中就会产生逆序对。

在冒泡排序中,数列中逆序对个数为冒泡排序中相邻两数交换总次数。

3、逆序对问题

[蓝桥杯 2014 省 B] 小朋友排队 - 洛谷

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值