算法竞赛入门经典训练指南(蓝书)Ping pong(UVaLive4329)树状数组

题意

在一个序列中,存在三个数为升序摆放或降序摆放,则这三个数可以视作能够举行比赛。问比赛的种数。

ps.升序或降序表示两个运动员之间的人中有人可以充当裁判,同时两个运动员愿意去裁判家中比赛。

思路

a 1 a_1 a1 a i − 1 a_{i-1} ai1 b i b_i bi 个数比 a i a_i ai 小,那么就有 i − 1 − b i i-1-b_i i1bi 个数比 a i a_i ai 大。所以我们可以记录 a i a_i ai 左边比 a i a_i ai 小的数与 a i a_i ai 右边比 a i a_i ai 小的数。

建立两个树状数组,边遍历序列边更新数组,树状数组的第 i i i 位记录当前比 i i i 小的数的个数。 l l l 数组正序遍历更新,代表 a i a_i ai 左边比 a i a_i ai 小的数。同理, r r r 数组倒序为右边比 a i a_i ai 小的数。

答案即为 ∑ 1 n [ l i × ( n − i − r i ) + ( i − 1 − l i ) × r i ] \sum_{1}^{n} [l_i \times (n-i-r_i)+(i-1-l_i) \times r_i] 1n[li×(niri)+(i1li)×ri]

Accepted code

/*
 * @Autor: CofDoria
 * @Date: 2021-03-06 19:14:39
 * @LastEditTime: 2021-03-08 16:55:47
 */
#include <bits/stdc++.h>
using namespace std;

#define db double
#define ll long long
#define lowbit(x) (x & -x)
#define inf 0x3f3f3f3f
#define s(a, n) memset(a, n, sizeof(a))
#define debug(a) cout << '#' << a << '#' << '\n'
#define rep(l, a, b) for (register ll l = a; l < b; ++l)
#define per(l, a, b) for (register ll l = a; l >= b; --l)
#define _ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define _forit(i, c) \
    for (__typeof__((c).begin()) i = (c).begin(); i != (c).end(); ++i)

bool fi = true;
const unsigned long long MOD = 1e9 + 7;

inline ll gcd(ll a, ll b) {
    
     return (b == 0 ? a : gcd(b, a % b)); }

ll t, n, a[100005];
ll l[100005], r[100005];
ll ansl[100005], ansr[100005];
ll ans;
// vector<int> q;

void addl(int x) {
    
    
    while (x <= 100000) ++l[x], x += lowbit(x);
}

ll suml(int x) {
    
    
    ll cnt = 0;
    while (x) cnt += l[x], x -= lowbit(x);
    return cnt;
}

void addr(int x) {
    
    
    while (x <= 100000) ++r[x], x += lowbit(x);
}

ll sumr(int x) {
    
    
    ll cnt = 0;
    while (x) cnt += r[x], x -= lowbit(x);
    return cnt;
}

int main() {
    
    
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    _ios;
    cin >> t;
    while (t--) {
    
    
        ans = 0;
        s(l, 0);
        s(r, 0);
        cin >> n;
        rep(i, 0, n) {
    
    
            cin >> a[i];
            ansl[i] = suml(a[i]);
            addl(a[i]);
        }
        per(i, n - 1, 0) {
    
    
            ansr[i] = sumr(a[i]);
            addr(a[i]);
            ans += ansr[i] * (i - ansl[i]) + ansl[i] * (n - 1 - i - ansr[i]);
        }
        cout << ans << '\n';
    }
    // fclose(stdin);
    // fclose(stdout);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46144509/article/details/114537761