0x42 数据结构进阶-树状数组

A题 楼兰图腾

链接:https://ac.nowcoder.com/acm/contest/1032/A

树状数组 + 逆序对

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & -x)
typedef long long ll;
const int maxn = 2e5 + 10;
int a[maxn], c[maxn], l[maxn], r[maxn], n;
void update(int p, int val) {
    while (p <= n) {
        c[p] += val;
        p += lowbit(p);
    }
}
 
int ask(int x) {
    int res = 0;
    while (x > 0) {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}
 
int main() {
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    //求正序,前面有几个比a[i]大
    for (int i = 1; i <= n; i++) {
        update(a[i], 1);
        l[i] = ask(a[i] - 1);
    }
    memset(c, 0, sizeof c);
    //树状数组清零求逆序,后面有几个比a[i]大
    for (int i = n; i >= 1; i--) {
        update(a[i], 1);
        r[i] = ask(a[i] - 1);
    }
    ll ans = 0;
    //依次枚举每个点作为中间点,以该点位中心的 ‘v’ 个数显然是 left[i] * right[i]
    for (int i = 2; i <= n - 1; i++) {
        ans += 1ll * (i - l[i] - 1) * (n - i - r[i]);
    }
    cout << ans << " ";
    ans = 0;
    //同理枚举 '^'的个数
    for (int i = 2; i <= n - 1; i++) {
        ans += 1ll * l[i] * r[i];
    }
    cout << ans << endl;
    return 0;
}

B题 A Tiny Problem with intergers

链接:https://ac.nowcoder.com/acm/contest/1032/B

树状数组 区间修改 + 单点查询

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & -x)
typedef long long ll;
const int maxn = 1e5 + 10;
int tr[maxn], n, q, a, pre;
void add(int i, int v) {
    while (i <= n) {
        tr[i] += v;
        i += lowbit(i);
    }
}
int getsum(int x) {
    int res = 0;
    while (x) {
        res += tr[x];
        x -= lowbit(x);
    }
    return res;
}
int main() {
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> q;
    for (int i = 1; i <= n; ++i)cin >> a, add(i, a - pre), pre = a;
    char c; int u, v, a;
    while (q--) {
        cin >> c >> u;
        if (c == 'C') {
            cin >> v >> a; add(u, a), add(v + 1, - a);
        }
        else
            cout << getsum(u) << endl;
    }
}

C题 A Simple Problem with Integers

链接:https://ac.nowcoder.com/acm/contest/1032/C

树状数组 区间修改 + 区间查询 / (线段树 or 分块)

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x & -x)
typedef long long ll;
const int maxn = 1e5 + 10;
ll n, q, tr1[maxn], tr2[maxn], a, pre;
void add(int x, int v) {
    for (int i = x; i <= n; i += lowbit(i)) tr1[i] += v, tr2[i] += 1ll * v * (x - 1);
}
ll getsum(int x) {
    long long sum = 0;
    for (int i = x; i; i -= lowbit(i)) sum += tr1[i] * x - tr2[i];
    return sum;
}
int main() {
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> q;
    for (int i = 1; i <= n; i++) cin >> a, add(i, a - pre), pre = a;
    char c; int u, v, a;
    while (q--) {
        cin >> c >> u >> v;
        if (c == 'C') {
            cin >> a; add(u, a), add(v + 1, - a);  
        }
        else
            cout << getsum(v) - getsum(u - 1) << endl;
    }
}

D题 Lost Cows

链接:https://ac.nowcoder.com/acm/contest/1032/D

树状数组 + 二分(or倍增)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
long long tr[maxn];
void add(int x, int v){
    if (x == 0)  return;
    while (x < maxn) {
        tr[x] += v;
        x += x & -x;
    }
}
long long query(int x){
    long long rec = 0;
    while (x) {
        rec += tr[x];
        x -= x & -x;
    }
    return rec;
}
int a[maxn], ans[maxn];
int main(){
    freopen("in.txt", "r", stdin);
    int n; scanf("%d", &n);
    for (int i = 2; i <= n; i++)
        scanf("%d", &a[i]);
    //二分,查询前mid个数有多少1比较,更新区间
    for (int i = n; i; i--) {
        int l = 1, r = n + 1, t;
        while (l <= r) {
            int mid = l + r >> 1;
            if (query(mid) + a[i] < mid)  t = mid, r = mid - 1;
            else   l = mid + 1;
        }
        ans[i] = t;
        add(t, 1);
    }
    for (int i = 1; i <= n; i++)
        printf("%d\n", ans[i]);
}
posted @ 2020-08-02 16:27  RioTian  阅读(188)  评论(1编辑  收藏  举报