LA4329 PingPong (线段树)

题意分析

这道题和逆序对的思路很相似。
首先可以想到的是,如果枚举两个人,然后算中间有几个裁判,不行。枚举两个人也要 O ( n 2 ) ,自然想到要枚举裁判。
如果要枚举裁判的话,其实就是求左边比裁判小,右边比裁判大,或者左边比裁判大,右边比裁判小的人数。 然后算个乘法求和即可。
自然就会想到求逆序对的个数那个题,统计方法类似的。然后推一个怎么统计答案的式子就好了。

代码总览

#include <bits/stdc++.h>
#define rep(i,a,b) for (int i = a; i<=b; ++i)
using namespace std;
const int nmax = 1e5 + 1000;
const int INF = 0x3f3f3f3f;
typedef long long ll;
typedef double db;
typedef struct {
    int l, r, val;
    int mid() {return (l + r) >> 1;}
} Tree;
Tree tree[nmax << 2];
ll L[nmax], R[nmax], a[nmax];
int t, n;
void pushup(int rt) {
    tree[rt].val = tree[rt << 1].val + tree[rt << 1 | 1].val;
}
void build(int l , int r, int rt) {
    tree[rt].l = l , tree[rt].r = r;
    tree[rt].val = 0;
    if (l == r) return;
    build(l, tree[rt].mid(), rt << 1);
    build(tree[rt].mid() + 1 , r, rt << 1 | 1);
}
void update(int pos , int rt) {
    if (tree[rt].l == tree[rt].r) {
        tree[rt].val = 1;
        return;
    }
    if (pos <= tree[rt].mid()) update(pos, rt << 1);
    else update(pos, rt << 1 | 1);
    pushup(rt);
}
ll query(int l , int r , int rt) {
    if (tree[rt].l >= l && tree[rt].r <= r) return tree[rt].val;
    if (r <= tree[rt].mid()) return (ll)query(l, r, rt << 1);
    else if (l > tree[rt].mid()) return (ll)query(l, r, rt << 1 | 1);
    else return (ll)query(l, tree[rt].mid(), rt << 1 ) + (ll)query(tree[rt].mid() + 1, r, rt << 1 | 1);
}
int main() {
    scanf("%d", &t);
    while (t--) {
        scanf("%d", &n);
        memset(L, 0, sizeof L);
        memset(R, 0, sizeof R);
        ll mx = 0;
        rep(i, 1, n) {scanf("%lld", &a[i]); mx = max(mx, a[i]);}
        build(1, mx, 1);
        rep(i, 1, n) {
            L[i] = query(1, a[i], 1);
            update(a[i], 1);
        }
        build(1, mx, 1);
        for (int i = n; i >= 1; --i) {
            R[i] = query(1, a[i], 1);
            update(a[i], 1);
        }
        ll ans = 0;
        rep(i, 1, n) {
            if (i == 1 || i == n) continue;
            else {
                ll temp = (ll) L[i] * ((ll)n - i - R[i]);
                ll temp2 = (ll) R[i] * ((ll)i - 1 - L[i]);
                ans += temp + temp2;
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pengwill97/article/details/80427396
今日推荐