『Luogu 1637』三元上升子序列 (树状数组)

Posted fang-hao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了『Luogu 1637』三元上升子序列 (树状数组)相关的知识,希望对你有一定的参考价值。

题目链接

题目描述

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』三元上升子序列 (树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P1637 三元上升子序列权值线段树By cellur925

洛谷P1637 三元上升子序列

P1637 三元上升子序列

P1637 三元上升子序列

P1637 三元上升子序列

洛谷 P1637 三元上升子序列Treap