正/逆序对+树状数组

树状数组是一个简化时间的东西,比较板,这里我就直接贴两个网址了

题目楼兰图腾(一位小朋友讲的但是讲的超级好)

https://www.bilibili.com/video/BV1P44y1m7Cs/?vd_source=01c1337d87eb586437097a72281b2a38

完整版树状数组讲解

https://blog.csdn.net/qq_41431457/article/details/88945833?app_version=5.11.1&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%2288945833%22%2C%22source%22%3A%22m0_62592071%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app

以下是几道题以及板子

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果然知识得应用才能学会

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值