題目大意
給定一個長度爲n的序列,
1.求所有點的左邊右邊比它大的數的個數, 兩邊的個數相乘, 所有的點求和,
2.求所有點的左邊右邊比它小的數的個數, 兩邊的個數相乘, 所有的點求和,
樣例
輸入樣例:
5
1 5 3 2 4
輸出樣例:
3 4
思路
利用樹狀數組求逆序對
代碼
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 200010;
ll c[N], r[N], l[N], a[N];
ll ans1, ans2;
int n;
int lowbit(int x)
{
return x & -x;
}
void add(int x, int v)
{
for(int i = x; i <= n; i += lowbit(i))
c[i] += v;
}
int query(int x)
{
int ans = 0;
for(int i = x; i > 0; i -= lowbit(i))
ans += c[i];
return ans;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", a + i);
for(int i = 1; i <= n; i++)
{
l[i] = query(a[i] - 1);
add(a[i], 1);
}
memset(c, 0, sizeof c);
for(int i = n; i > 0; i--)
{
r[i] = query(a[i] - 1);
add(a[i], 1);
}
for(int i = 1; i <= n; i++)
ans1 += l[i] * r[i];
memset(c, 0, sizeof c);
for(int i = 1; i <= n; i++)
{
l[i] = query(n) - query(a[i]);
add(a[i], 1);
}
memset(c, 0, sizeof c);
for(int i = n; i >= 1; i--)
{
r[i] = query(n) - query(a[i]);
add(a[i], 1);
}
for(int i = 1; i <= n; i++)
ans2 += l[i] * r[i];
printf("%lld %lld", ans2, ans1);
return 0;
}