《算法竞赛进阶指南》0x42树状数组 楼兰图腾

题目链接:https://www.acwing.com/problem/content/243/

给定一个全排列,对于每个位置,都求前面有多少个数比它小,有多少个数比他大,右边有多少个数比他小有多少个数比他大。通过树状数组可以在O(nlogMAX)时间内求出。

代码:

#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
const int maxn = 200010;
int c[maxn];
int a[maxn];
int lmin[maxn],lmax[maxn],rmin[maxn],rmax[maxn];
int lowbit(int x){return x&(-x);}
int query(int x){
    int ans=0;
    while(x){
        ans+=c[x];
        x-=lowbit(x);
    }
    return ans;
}
void update(int x,int C){
    while(x<maxn){
        c[x]+=C;
        x+=lowbit(x);
    }
}
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
        lmin[i]=query(a[i]-1);
        lmax[i]=i-1-lmin[i];
        update(a[i],1);
    }
    memset(c,0,sizeof(c));
    for(int i=n;i;i--){
        rmin[i]=query(a[i]-1);
        rmax[i]=n-i-rmin[i];
        update(a[i],1);
    }
    long long ans1=0,ans2=0;
    for(int i=2;i<=n-1;i++){
        ans2+=(long long)lmin[i]*rmin[i];
        ans1+=(long long)lmax[i]*rmax[i];
    }
    cout<<ans1<<" "<<ans2<<endl;
}
原文地址:https://www.cnblogs.com/randy-lo/p/13294950.html