树状数组的运用

树状数组

树状数组基本功能:

int lowbit(int x) { return x & (-x); }
struct BIT
{
	int c[N];
	int query(int x)
	{
		int ans = 0;
		for (int i = x; i >= 1; i -= lowbit(i))
			ans += c[i];
		return ans;
	}
	void add(int x, int k)
	{
		for (int i = x; i <= n; i += lowbit(i))
			c[i] += k;
	}
}bit;

求第 k k k小的数

可以先想到的是二分 + q u e r y +query +query
复杂度为 O ( n   l o g 2 n ) O(n\ log^2n) O(n log2n)
我们可以用倍增来优化
详见代码:

void kth(int k)
{
	int x = 0, sum = 0;
	for (int i = 20; i >= 0; --i)
	{
		x += (1 << i);				// 尝试找到更小的
		if (x >= n || sum + c[x] >= k)  // 没有找到更小的
			x -= (1 << i);			// 将操作退回
		else sum += c[x];			// 找到更小的
	}
	return x + 1;
}

优化

O ( n ) O(n) O(n)建树

void init()
{
	for (int i = 1; i <= n; ++i)
	{
		t[i] += a[i];
		int j = i + lowbit(i);
		if (j <= n) t[j] += t[i];
	}
}

时间戳清空

int T, tag[N];
int query(int x)
{
	int ans = 0;
	for (int i = x; i; i -= lowbit(i))
		if (T == tag[i])
			ans += c[i];
	return ans;
}
void add(int x, int k)
{
	for (int i = x; i <= n; i += lowbit(i))
	{
		if (T != tag[i])
			tag[i] = T, c[i] = 0;
		c[i] += k;
	}
}
void clear() { ++T;	}

全面

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

struct BIT
{
	int c[N], T, tag[N];
	int query(int x)
	{
		int ans = 0;
		for (int i = x; i; i -= lowbit(i))
			if (T == tag[i])
				ans += c[i];
		return ans;
	}
	void add(int x, int k)
	{
		for (int i = x; i <= n; i += lowbit(i))
		{
			if (T != tag[i])
				tag[i] = T, c[i] = 0;
			c[i] += k;
		}
	}
	void clear() { ++T;	}
	int query(int l, int r) { return query(r) - query(l - 1); }\
	void init()
	{
		for (int i = 1; i <= n; ++i)
		{
			t[i] += a[i];
			int j = i + lowbit(i);
			if (j <= n) t[j] += t[i];
		}
	}
}bit;

二维数点

Q:我们如何快速求出矩阵中有多少个点呢?
我们可以用前缀和
Q:数据很大,或者有负数怎么办?
用离散化把数据压到 n 2 n^2 n2个点
Q: n n n很大呢?
树状数组
我们拿一道题:

P2163 [SHOI2007] 园丁的烦恼

思路

将一个询问拆成四个询问,分别处理。

代码

#include <bits/stdc++.h>
#define ll long long
#define PII pair<int, int>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7, N = 5e5 + 5, M = 1e7 + 5;
int n, m, k, ans[N], mp[N * 4], len;

int lowbit(int x) { return x & (-x); }
struct BIT
{
	int c[N];
	int query(int x)
	{
		int ans = 0;
		for (int i = x; i >= 1; i -= lowbit(i))
			ans += c[i];
		return ans;
	}
	void add(int x, int k)
	{
		for (int i = x; i <= n; i += lowbit(i))
			c[i] += k;
	}
}bit;

struct P
{
	int x, y;
	bool friend operator< (P x, P y) { return x.x < y.x; } 
}tre[N];

// 记录询问的结构体
struct Query
{
	int x, y, id, flag;	
	// x,y表示要求的矩阵的右上方, id表示询问的编号,flag表示是正的还是负的。
	bool friend operator< (Query x, Query y) { return x.x < y.x; } 
}q[N * 4]; // 别忘了空间*4

int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i)
		scanf("%d%d", &tre[i].x, &tre[i].y), mp[++len] = tre[i].y;
	for (int i = 1, a, b, c, d; i <= m; ++i)
	{
		scanf("%d%d%d%d", &a, &b, &c, &d);
		q[++k] = {c, d, i, 1};
		q[++k] = {a - 1, b - 1, i, 1};
		q[++k] = {c, b - 1, i, -1};
		q[++k] = {a - 1, d, i, -1};
		mp[++len] = b - 1, mp[++len] = d;
	}
	sort(mp + 1, mp + 1 + len);
	len = unique(mp + 1, mp + 1 + len) - mp - 1;
	sort(q + 1, q + 1 + k);
	sort(tre + 1, tre + 1 + n);
	for (int i = 1; i <= n; ++i)
		tre[i].y = lower_bound(mp + 1, mp + 1 + len, tre[i].y) - mp;
	for (int i = 1; i <= k; ++i)
		q[i].y = lower_bound(mp + 1, mp + 1 + len, q[i].y) - mp;
    for (int i = 1, j = 1; i <= k; i++)
	{
        while (j <= n && tre[j].x <= q[i].x) bit.add(tre[j++].y, 1);
        ans[q[i].id] += q[i].flag * bit.query(q[i].y);
    }
    for (int i = 1; i <= m; i++) printf("%d\n", ans[i]);
	return 0;
}
  • 17
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值