树状数组POJ-2299





树状数组(详细分析+应用),看不懂打死我!-CSDN博客

参考:

单点修改,区间查询

#include <bits/stdc++.h>
using namespace std;
/*
树状数组实现单点修改
区间查询
*/
int N;
int tree[100];
int lowbit(int x) {
	return x & (-x);
}
void add(int k,int n) {
	while (k <= N) {
		tree[k] += n;
		k += lowbit(k);
	}
}
int query(int l,int r) {
	int res = 0;
	for (int i = l - 1; i; i -= lowbit(i))
		res -= tree[i];
	for (int i = r; i; i -= lowbit(i))
		res += tree[i];
	return res;
}
int main() {
	cin >> N;
	for (int i = 1; i <= N; i++)
	{
		int num;
		cin >> num;
		add(i, num);
	}
	cout << query(1, 3);
}

区间修改,单点查询

#include <bits/stdc++.h>
using namespace std;
/*
树状数组实现单点修改
区间查询
*/
int N;
int a[100];
int tree[100];//储存前缀和数组
int lowbit(int x) {
	return x & (-x);
}
void add(int k,int n) {
	while (k <= N) {
		tree[k] += n;
		k += lowbit(k);
	}
}
int query(int l,int r) {
	int res = 0;
	for (int i = l - 1; i; i -= lowbit(i))
		res -= tree[i];
	for (int i = r; i; i -= lowbit(i))
		res += tree[i];
	return res;
}
int main() {

	cin >> N;
	a[0] = 0;
	for (int i = 1; i <= N; i++) {
		cin >> a[i];
		add(i, a[i] - a[i - 1]);
	}
	//实现区间修改 l r num 1 3 +2
	add(1, 2);
	add(4, -2);
	//实现单点查询 查询1
	cout << tree[1];
}

区间修改,区间查询

这一类操作使用树状数组就显得及其复杂,这时候我们建议使用扩展性更强的线段树来解决,在此就不进行树状数组的讲解了.

接下来是我自己的理解:

树状数组是为了解决一些单点修改 区间查询的问题 如果加上差分数组可以用来解决区间修改和单点查询问题 由于编程简单可以用来替代一些线段树的情况 但不是绝对的

难一点的题就是逆序对:

也就是poj-2299

本题的关键是逆序对:i>j a[i]<a[j]为一个逆序对

只能相邻的交换 本题转换为消除所有的逆序对需要多少次 一次只能消除一对 求逆序对总数

利用树状数组实现同时离散化

#include <bits/stdc++.h>
using namespace std;

/*
树状数组实现单点修改
区间查询
*/

struct node {
    int value;
    int id; // 表示出现顺序 用来表示插入顺序
    bool operator<(node& n) const { return value < n.value; }
};

int N;
int Rank[500004];
int tree[500004];

int lowbit(int x) {
    return x & (-x);
}

void add(int k, int n) {
    while (k <= N) {
        tree[k] += n;
        k += lowbit(k);
    }
}

int query(int l, int r) {
    int res = 0;
    for (int i = l - 1; i; i -= lowbit(i))
        res -= tree[i];
    for (int i = r; i; i -= lowbit(i))
        res += tree[i];
    return res;
}

vector<node> n;

int main() {
    while (cin >> N && N != 0) {
        n.clear();
        n.resize(N + 1);
        fill(tree, tree + N + 1, 0); // 重置树状数组

        for (int i = 1; i <= N; i++) {
            cin >> n[i].value;
            n[i].id = i;
        }

        sort(n.begin() + 1, n.end());

        for (int i = 1; i <= N; i++) {
            Rank[n[i].id] = i;
        }

        int ans = 0;
        for (int i = 1; i <= N; i++) {
            int pos = Rank[i];
            ans += query(pos + 1, N); // digit+1~n中有多少数字已经出现就贡献多少逆序对数,累加到答案 
            add(pos, 1); // 单点修改
        }

        cout << ans << endl; // 输出结果
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值