P10589 樓蘭圖騰

一位XXS發表於2024-10-12

Problem

有n個記號在一面牆上從左往右排列,其離地面高度\(h_i\)不同,保證是1~n的一個排列,試求出有多少種如下兩種情況

\[①i<j<k \]

\[②h_i>h_j<h_k或h_i<h_j>h_k \]

其中在滿足①②的情況下②分左右兩種,\(n\le2\times10^5\)\(Ans\le2^{64}-1\)

Solve

可以列舉每個\(i,j,k\)計算滿足哪些情況,時間複雜度\(O(n^3)\)
但其實我們可以維護兩個值域線段樹,分別計算在i的前面與後面大於或小於\(h_j\)的個數
以V字(第一種)情況舉例,設在p節點,在它前面有u個數比他大,在後面有v個數比它大,那麼不難得出當\(j=p\)時,會為答案產生\(u\times v\)的貢獻,這樣時間複雜度就變成了\(O(n\log n)\)

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<list>
#include<map>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
long long n,a[200005],s[800005],ans[5][200005];
void upd(int p,int l,int r,int x,long long v){
    if(l>x||r<x)return ;
    if(l==r){
        s[p]++;
        return ;
    }
    upd(2*p,l,(l+r)/2,x,v);
    upd(2*p+1,(l+r)/2+1,r,x,v);
    s[p]++;
}
long long qsum(int p,int l,int r,int x,int y){
    if(x>r||y<l)return 0;
    if(l>=x&&r<=y)return s[p];
    long long ans=0;
    ans+=qsum(2*p,l,(l+r)/2,x,y);
    ans+=qsum(2*p+1,(l+r)/2+1,r,x,y);
    return ans;
}
int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        upd(1,1,n,a[i],1);
        ans[1][i]+=qsum(1,1,n,a[i]+1,n);
        ans[2][i]+=qsum(1,1,n,1,a[i]-1);
    }
    memset(s,0,sizeof(s));
    for(int i=n;i>=1;i--){
        upd(1,1,n,a[i],1);
        ans[3][i]+=qsum(1,1,n,a[i]+1,n);
        ans[4][i]+=qsum(1,1,n,1,a[i]-1);
    }
    long long res=0,res1=0;
    for(int i=1;i<=n;i++){
        res+=ans[1][i]*ans[3][i];
        res1+=ans[2][i]*ans[4][i];
    }
    cout<<res<<" "<<res1;
    return 0;
}

相關文章