树状数组
树状数组
逆序对
#include <iostream>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
const int N = 5e5 + 10;
int tr[N], ranks[N], n;
int ans;
struct point
{
int num, val;
bool operator<(const point &x) const
{
if (val == x.val)
return num < x.num;
return val < x.val;
}
}a[N];
int lowbit(int x)
{
return x & -x;
}
void add(int idx, int x)
{
for (int i = idx; i <= n; i += lowbit(i))
tr[i] += x;
}
int sum(int idx)
{
int s = 0;
for (int i = idx; i; i -= lowbit(i))
s += tr[i];
return s;
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].val, a[i].num = i;
sort(a + 1, a + n + 1);
for (int i = 1; i <= n; i++)
ranks[a[i].num] = i;
for (int i = 1; i <= n; i++)
{
add(ranks[i], 1);
ans += i - sum(ranks[i]);
}
cout << ans << endl;
return 0;
}
差分实现区间修改,单点查询
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, m;
int tr[N];
int lowbit(int x)
{
return x & -x;
}
void add(int idx, int k)
{
for (int i = idx; i < N; i += lowbit(i))
tr[i] += k;
}
int sum(int idx)
{
int ans = 0;
for (int i = idx; i; i -= lowbit(i))
ans += tr[i];
return ans;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
while(m--)
{
int t;
cin >> t;
if (t == 1)
{
int l, r;
cin >> l >> r;
add(l, 1), add(r + 1, -1);
}
else
{
int x;
cin >> x;
cout << (sum(x) & 1) << endl;
}
}
return 0;
}
前缀最值 + 单点修改
利用二维偏序优化最长上升子序列 \(i<j,a[i]<a[j]\)
本题求的是最长下降子序列
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 1e6 + 10, INF = 1e9;
int n;
int a[N], f[N], tr[N];
int lowbit(int x)
{
return x & -x;
}
void update(int x, int k)
{
for (int i = x; i < N; i += lowbit(i))
tr[i] = max(tr[i], k);
}
int query(int x)
{
int ans = 0;
for (int i = x; i; i -= lowbit(i))
ans = max(ans, tr[i]);
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
int ans = 1;
for (int i = 1; i <= n; i++)
tr[i] = 0;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]), a[i] = n + 1 - a[i];//将逆序对变为正序对
for (int i = 1; i <= n; i++)
{
f[i] = query(a[i]) + 1;
update(a[i], f[i]);
ans = max(ans, f[i]);
}
printf("%d\n", ans);
for (int i = 1; i <= n; i++)
printf("%d ", f[i]);
puts("");
}
return 0;
}
二维树状数组
JSOI2009]计数问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long ll;
const int N = 3e2 + 10;
int n, m, q;
int tr[N][N][110];
int a[N][N];
int lowbit(int x)
{
return x & -x;
}
void add(int x, int y, int c, int k)
{
for (int i = x; i < N; i += lowbit(i))
for (int j = y; j < N; j += lowbit(j))
tr[i][j][c] += k;
}
int sum(int x, int y, int c)
{
int ans = 0;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
ans += tr[i][j][c];
return ans;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
int x;
cin >> x;
a[i][j] = x;
add(i, j, x, 1);
}
}
cin >> q;
while(q--)
{
int op;
cin >> op;
if (op == 1)
{
int x, y, c;
cin >> x >> y >> c;
int last = a[x][y];
add(x, y, c, 1);
add(x, y, last, -1);
a[x][y] = c;
}
else
{
int x1, y1, x2, y2, c;
cin >> x1 >> x2 >> y1 >> y2 >> c;
cout << sum(x2, y2, c) - sum(x1-1, y2, c) - sum(x2, y1-1, c) + sum(x1-1, y1-1, c) << endl;
}
}
return 0;
}
类模板
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, q;
ll a[N];
template<class T>
struct BIT
{
T tr[N];
int size;
void resize(int s) {size = s;}
T query(int x)
{
T s = 0;
for ( ; x; x -= x & -x)
s += tr[x];
return s;
}
void modify(int x, T s)
{
for ( ; x <= size; x += x & -x)
tr[x] += s;
}
};
BIT<ll> c;
树状数组上二分
http://oj.daimayuan.top/course/15/problem/636
若在权值上开树状数组,则可以求第 k 大的数 \(O(nlogn)\)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, q;
ll a[N];
template<class T>
struct BIT
{
T tr[N];
int size;
void resize(int s) {size = s;}
int query(T s)
{
int pos = 0;
for (int j = 18; j >= 0; j--)
{
if (pos + (1 << j) <= n && tr[pos + (1 << j)] <= s)
{
pos += (1 << j);
s -= tr[pos];
}
}
return pos;
}
void modify(int x, T s)
{
for ( ; x <= size; x += x & -x)
tr[x] += s;
}
};
BIT<ll> c;
二维数点
http://oj.daimayuan.top/course/15/problem/686
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <array>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int n, q, m;
int tr[N], ans[N];
vector<int> alls;
vector<array<int, 4> > event;
int lowbit(int x)
{
return x & -x;
}
int query(int idx)
{
int ans = 0;
for (int i = idx; i; i -= lowbit(i))
ans += tr[i];
return ans;
}
void modify(int idx, int k)
{
for (int i = idx; i <= m; i += lowbit(i))
tr[i] += k;
}
int main()
{
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++)
{
int x, y;
scanf("%d%d", &x, &y);
alls.push_back(x);
event.push_back({y, 0, x});
}
for (int i = 1; i <= q; i++)
{
int x1, x2, y1, y2;
scanf("%d%d%d%d", &x1, &x2, &y1, &y2);
event.push_back({y2, 1, x2, i});
event.push_back({y1 - 1, 2, x2, i});
event.push_back({y2, 2, x1 - 1, i});
event.push_back({y1 - 1, 1, x1 - 1, i});
}
sort(event.begin(), event.end());
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
m = alls.size();
for (auto evt : event)
{
if (evt[1] == 0)
{
int idx = lower_bound(alls.begin(), alls.end(), evt[2]) - alls.begin() + 1;
modify(idx, 1);
}
else
{
int idx = upper_bound(alls.begin(), alls.end(), evt[2]) - alls.begin();
if (evt[1] == 1)
ans[evt[3]] += query(idx);
else
ans[evt[3]] -= query(idx);
}
}
for (int i = 1; i <= q; i++)
printf("%d\n", ans[i]);
return 0;
}