树状数组
树状数组基本功能:
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;
}