核心代码
ll sum(ll i){
ll s = 0;
while(i > 0){
s += c[i];
i -= i & -i;
}
return s;
}
ll add(ll i, ll x){
while(i <= n){
c[i] += x;
i += i & -i;
}
}
sum 子函数可以 求出前i项和, add子函数 可以求出 把x加到i项
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define ll long long
ll c[100010];
ll left_[100010];
ll right_[100010];
ll vis[100010];
ll n;
ll sum(ll i){
ll s = 0;
while(i > 0){
s += vis[i];
i -= i & -i;
}
return s;
}
ll add(ll i, ll x){
while(i <= 100010){
vis[i] ++;
i += i & -i;
}
}
int main (){
ll num;
scanf("%lld",&num);
while(num--){
scanf("%lld",&n);
memset(vis,0,sizeof(vis));
memset(vis,0,sizeof(left_));
memset(vis,0,sizeof(right_));
memset(vis,0,sizeof(c));
for(ll i = 1; i <= n; i++){
scanf("%lld",&c[i]);
}
for(ll i = 1 ; i <= n ; i++){
left_[i] = sum(c[i]);
add(c[i],1);
}
memset(vis,0,sizeof(vis));
for(ll i = n; i >= 1 ; i--){
right_[i] = sum(c[i]);
add(c[i],1);
}
ll sum = 0;
for(ll i = 1; i <= n; i++){
sum += (ll)(n - i - right_[i])*left_[i] + (ll)(i - left_[i] - 1)*right_[i];
}
printf("%lld\n",sum);
}
return 0;
}
树状数组
最新推荐文章于 2021-06-14 20:31:04 发布