1. 程式人生 > >『Luogu 1637』三元上升子序列 (樹狀數組)

『Luogu 1637』三元上升子序列 (樹狀數組)

algo gis name long long stream namespace spa href 樹狀

題目鏈接

題目描述

Erwin最近對一種叫"thair"的東西巨感興趣。。。

在含有\(n\)個整數的序列\(a_1,a_2 \dots a_n\)中,

三個數被稱作"thair"當且僅當\(i<j<k\)\(a_i<a_j<a_k\)

求一個序列中"thair"的個數。


解題思路

典型的偏序問題,我們固定\(j\)的位置,問題就變成了在\(j\)前面有多少個數比\(a_j\)小,在\(j\)後面有多少數比\(a_j\)大,答案顯然就是兩個的乘積。

顯然,可以用主席樹做

當然,我是來練習樹狀數組的【霧】,所以就拿樹狀數組寫吧。。。。

首先,我們從後向前掃一遍,可以得到比當前大的有多少個(借助桶排序的思路)。

同理,我們從前向後掃一遍,可以得到比當前小的有多少個。

然後統計答案就OK了。

辣雞lower_bound WA了十幾次嗚嗚嗚嗚o(TヘTo)



代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const ll maxn=40050;
ll n,len;
ll a[maxn],b[maxn],aa[maxn];
ll shun[maxn],ni[maxn];
ll num[maxn<<2];
inline ll lowbit(ll x){return x&(-x);}
inline ll query(ll x){
    ll ans=0;
    while(x>0){
        ans+=num[x];
        x-=lowbit(x);
    }
    return ans;
}
inline void add(ll x){
    while(x<(maxn<<2)){
        num[x]++;
        x+=lowbit(x);
    }
}
int main(){
    scanf("%lld",&n);
    for(register int i=1;i<=n;i++)scanf("%lld",&a[i]),b[i]=a[i];
    sort(b+1,b+n+1);
    len=unique(b+1,b+n+1)-(b+1);
    for(register int i=1;i<=n;i++)aa[i]=lower_bound(b+1,b+len+1,a[i])-(b+1);
    for(register int i=1;i<=n;i++)aa[i]+=2;
    len+=100;
    for(register int i=n;i>=1;i--){
        ni[i]=query(len-aa[i]-1);
        add(len-aa[i]);
    }
    memset(num,0,sizeof(num));
    for(register int i=1;i<=n;i++){
        shun[i]=query(aa[i]-1);
        add(aa[i]);
    }
    long long ans=0;
    for(register int i=1;i<=n;i++)ans=ans+shun[i]*ni[i];
    cout<<ans<<endl;
}

『Luogu 1637』三元上升子序列 (樹狀數組)