1. 程式人生 > >【CH4201】樓蘭圖騰

【CH4201】樓蘭圖騰

題目大意:給定一個長度為 N 的序列,從序列中任意挑出三個數,求滿足中間的數字值最小(最大)有多少種情況。

題解:建立在值域上的樹狀陣列,從左到右掃描一遍序列,統計出每個點左邊有多少個數大於(小於)該點的值,再從右到左掃描一遍序列,統計出每個點右邊有多少個數大於(小於)自己,最後計算答案貢獻即可。

程式碼如下

#include <bits/stdc++.h>
#define cls(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&-x
#define all(x) x.begin(),x.end()
using namespace std;
const int maxn=2e5+10;

inline int read(){
    int x=0,f=1;char ch;
    do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
    do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
    return f*x;
}

int n,a[maxn],bit[maxn],left1[maxn],left2[maxn],right1[maxn],right2[maxn];
long long ans1,ans2;

void read_and_parse(){
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
}

inline void modify(int x,int val){
    for(int i=x;i<=n;i+=lowbit(i))bit[i]+=val;
}
inline int query(int x){
    int ans=0;
    for(int i=x;i;i-=lowbit(i))ans+=bit[i];
    return ans;
}

void solve(){
    for(int i=1;i<=n;i++){
        left1[i]=query(a[i]-1);
        left2[i]=query(n)-query(a[i]);
        modify(a[i],1);
    }
    cls(bit,0);
    for(int i=n;i>=1;i--){
        right1[i]=query(a[i]-1);
        right2[i]=query(n)-query(a[i]);
        modify(a[i],1);
    }
    for(int i=1;i<=n;i++)ans1+=(long long)left2[i]*right2[i],ans2+=(long long)left1[i]*right1[i];
    printf("%lld %lld\n",ans1,ans2);
}

int main(){
    read_and_parse();
    solve();
    return 0;
}