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;
}