树状数组是一个简化时间的东西,比较板,这里我就直接贴两个网址了
题目楼兰图腾(一位小朋友讲的但是讲的超级好)
https://www.bilibili.com/video/BV1P44y1m7Cs/?vd_source=01c1337d87eb586437097a72281b2a38
完整版树状数组讲解
以下是几道题以及板子
A Youth Finale
题目来源:2022 China Collegiate Programming Contest (CCPC) Guilin Site
这个题不单单是树状数组那么简单,需要先推一些过程(具体思路我就不在这篇写了,会在之后的文章里面写思路)。我们队当时vp写这个题思路是很正确的,但是在过第七组案例的时候tle了,抄上树状数组的板子后就过了
#include <bits/stdc++.h>
using namespace std;
const int mod = 10;
typedef long long ll;
ll n, m;
ll t[300000 + 5];
ll lowbit(ll x) {
return x & -x;
}
void add(ll x) {
while (x <= n) {
t[x]++;
x += lowbit(x);
}
}
ll summ(ll x) {
ll ans = 0;
while (x) {
ans += t[x];
x -= lowbit(x);
}
return ans;
}
int main() {
cin >> n >> m;
ll a[n + 5];
ll b[n + 5];
ll cnt = 0;
for (ll i = 1; i <= n; i++) {
cin >> a[i];
add(a[i]);
cnt += i - summ(a[i]);
}
string s;
cin >> s;
//ll cnt = bubble_sort(b, n);
cout << cnt << endl;
ll k = 1;
ll sum = cnt;
ll flag = 0;
ll pos;
a[0] = a[n];
for (ll i = 0; i < m; i++) {
if (k < 1) {
k += n;
}
if (k > n) {
k -= n;
}
if (s[i] == 'S' && flag == 0) {
sum = sum - abs(a[k % n ] - 1) + n - a[k % n];
cout << sum % mod;
k++;
}
if (s[i] == 'R') {
sum = n * (n - 1) / 2 - sum;
if (flag == 0) {
flag = 1;
k--;
} else {
flag = 0;
k++;
}
//flag=1-flag;
cout << sum % 10;
}
if (s[i] == 'S' && flag == 1) {
//cout<<a[k%n]<<' '<<k<<endl;
sum = sum - abs(a[k % n] - 1) + (n - a[k % n]);
cout << sum % mod;
k--;
}
}
}
B Maximum Crossings
Codeforces Round #790 (Div. 4)
突然发现div4的题现在基本已经可以补完了(场上的时间还是不太够的)(说起来#790这也是鄙人打的第一场cf)(其实思路很简单,就是求整个数组的逆序对有几个,求出来的总和就是答案)
#include <bits/stdc++.h>
using i64 = long long;
template <typename T>
struct Fenwick {
const int n;
std::vector<T> a;
Fenwick(int n) : n(n), a(n) {}
void add(int x, T v) {
for (int i = x + 1; i <= n; i += i & -i) {
a[i - 1] += v;
}
}
T sum(int x) {
T ans = 0;
for (int i = x; i > 0; i -= i & -i) {
ans += a[i - 1];
}
return ans;
}
T rangeSum(int l, int r) {
return sum(r) - sum(l);
}
};
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; i++) {
std::cin >> a[i];
a[i]--;
}
Fenwick<int> fen(n);
i64 ans = 0;
for (int i = n - 1; i >= 0; i--) {
ans += fen.sum(a[i] + 1);
fen.add(a[i], 1);
}
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
solve();
}
return 0;
}
C 楼兰图腾
这个题是当时女生赛训练赛的,也是Acwing241的题目,算经典板题了(分两种情况,^和v,然后分别用树状数组求,然后答案累加)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int c[1000010];
int a[1000010];
int l[1000010];
int r[1000010];
int n;
int ask(int x) {
int ans = 0;
for (; x; x -= x & (-x))
ans += c[x];
return ans;
}
void add(int x, int y) {
for (; x <= n; x += x & -x)
c[x] += y;
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
memset(c, 0, sizeof(c));
for (int i = n; i; i--) {
r[i] = ask(a[i] - 1);
add(a[i], 1);
}
memset(c, 0, sizeof(c));
for (int i = 1; i <= n; i++) {
l[i] = ask(a[i] - 1);
add(a[i], 1);
}
ll ans1 = 0;
for (int i = 1; i <= n; i++) {
ans1 += (ll)(n - i - r[i]) * (i - 1 - l[i]);
}
ll ans2 = 0;
for (int i = 1; i <= n; i++)
ans2 += (ll)r[i] * l[i];
cout << ans1 << " " << ans2 << " ";
}
D Rooks Defenders
Codeforces Round #791 (Div. 2)
知道把横纵抽象成两个数组然后横纵分别用树状数组就行(这个题它卡cin,得写ios::那句或者写scanf)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define sf(x) scanf("%lld",&x);
int n;
const int N = 1e6;
int a[N];
int b[N];
int lowbit(int x) {
return x & -x;
}
void add(int x, int v) {
int t = x;
while (t <= n) {
a[t] += v;
t += lowbit(t);
}
}
int sum(int x) {
int ans = 0;
while (x) {
ans += a[x];
x -= lowbit(x);
}
return ans;
}
void addd(int x, int v) {
while (x <= n) {
b[x] += v;
x += lowbit(x);
}
}
int summ(int x) {
int ans = 0;
while (x) {
ans += b[x];
x -= lowbit(x);
}
return ans;
}
signed main() {
int q;
cin >> n >> q;
map<int, int>mp1, mp2;
mp1.clear();
mp2.clear();
while (q--) {
int c;
sf(c);
if (c == 1) {
int x, y;
sf(x);
sf(y);
if (mp1[x] == 0)
add(x, 1);
if (mp2[y] == 0)
addd(y, 1);
mp1[x]++;
mp2[y]++;
}
if (c == 2) {
int x, y;
sf(x);
sf(y);
if (mp1[x] == 1)
add(x, -1);
if (mp2[y] == 1)
addd(y, -1);
mp1[x]--;
mp2[y]--;
}
if (c == 3) {
int x, y, p, q;
sf(x);
sf(y);
sf(p);
sf(q);
int t = sum(p) - sum(x - 1);
//cout << sum(p) << " " << sum(x - 1) << endl;
int s = summ(q) - summ(y - 1);
//cout << summ(q) << " " << summ(y - 1) << endl;
if (t == (p - x + 1 ) || s == (q - y + 1))
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
}
总之,树状数组就是板题(无脑背板子就好)
后言:没想到前一天晚上刚总结完树状数组,后天我见到题就想不起来o(╥﹏╥)o果然知识得应用才能学会