P1637 三元上升子序列

题目链接:https://www.luogu.com.cn/problem/P1637

思路

Lcnt[i]表示位置i,左边有多少个小于arr[i]
Rcnt[i]表示位置i,右边有多少个大于arr[i]
所以左右可以分别进行搞一次权值线段树,线段树存的是[l,r]之间的元素当前出现的总次数。
因为arr[i]是longlong范围,所以需要进行离散化一下.

代码

#include<bits/stdc++.h>
#define ios ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define debug  freopen("in.txt","r",stdin),freopen("out.txt","w",stdout);
using namespace std;
typedef long long ll;
const int maxn = 3e4+10;
using namespace std;

int N;
int Lcnt[maxn],Rcnt[maxn];
ll arr[maxn];
int pos[maxn],tail;
struct node{
    int l,r,cnt;
}tr[maxn*4];
struct node2
{
    ll v,id;
    bool operator< (const node2 & o) const{
        return v<o.v;
    }
}cpy[maxn];

void pushup(int u){
    tr[u].cnt = tr[u*2].cnt + tr[u*2+1].cnt;
}
void build(int l,int r,int u = 1){
    tr[u] = {l,r,0};
    if(l == r) return ;
    int mid = (l+r)>>1;
    build(l,mid,u*2);
    build(mid+1,r,u*2+1);
    pushup(u);
}
void modify(int idx,int v,int u = 1){
    if(tr[u].l == idx && tr[u].r == idx) tr[u].cnt += 1;
    else{
        int mid = (tr[u].l + tr[u].r)>>1;
        if(idx<=mid) modify(idx,v,u*2);
        else modify(idx,v,u*2+1);
        pushup(u);
    }
}
int query(int l,int r,int u = 1){
    if(l <= tr[u].l && tr[u].r <= r) return tr[u].cnt;
    else{
        int mid = (tr[u].l + tr[u].r)>>1;
        int sum = 0;
        if(l<=mid) sum += query(l,r,u*2);
        if(r>mid) sum += query(l,r,u*2+1);
        return sum;
    }
}

void Lisa(){ //离散化,类似于桶排序,离散化之后,愿下标i对于pos[i]
    sort(cpy+1,cpy+N+1);
    for(int i = 1;i<=N;i++){
        if(cpy[i].v != cpy[i-1].v) pos[cpy[i].id] = ++tail;
        else pos[cpy[i].id] = tail;
    }
}


int main(){
    // debug;
    ios;
    cin>>N;
    for(int i = 1;i<=N;i++) {
        cin>>arr[i];
        cpy[i] = {arr[i],i};
    }
    Lisa();
    build(1,tail);
    for(int i = 1;i<=N;i++){ //从左到右
        if(1<=pos[i]-1) Lcnt[i] = query(1,pos[i]-1);
        modify(pos[i],1);
    }
    build(1,tail);
    for(int i = N;i>=1;i--){//从右到左
        if(pos[i]+1 <= tail) Rcnt[i] = query(pos[i]+1,tail);
        modify(pos[i],1);
    }
    ll res = 0;
    for(int i = 1;i<=N;i++){
        res += (ll)Lcnt[i] * Rcnt[i];
    }
    cout<<res<<endl;

    return 0;
}