《算法竞赛进阶指南》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; }
每一个不曾起舞的日子,都是对生命的辜负。