Luogu P1637 삼항 오름차순 하위 시퀀스
제목 설명
Erwin은 최근 thair라는 것에 매우 관심을 갖게되었습니다. . .
nn 포함n 개의 정수 시퀀스a 1, a 2,…, a_1, a_2, \ ldots, a_nㅏ(1),ㅏ이,…,ㅏNi <j <k i <j <k 인 경우에만 세 개의 숫자를 thair라고합니다.나는<제이<k且ai <aj <ak a_i <a_j <a_kㅏ나는<ㅏJ<ㅏ케이。
시퀀스에서 thair의 수를 찾으십시오.
입력 형식
양의 정수 nn 으로 줄 시작n ,
다음 줄 nnn个整수a 1, a 2, ..., an a_1, a_2, \ ldots, a_nㅏ(1),ㅏ이,…,ㅏN。
출력 형식
한 줄의 정수는 thair의 수를 나타냅니다.
견본
# 1 입력
4
2 1 3 4
출력 # 1
2
입력 # 2
5
1 2 2 3 4
출력 # 2
7
일반적인 가중 선분 트리는 먼저 데이터를 이산화 한 다음 각 숫자에 대해 a [i] a [i]a [ i ] 선분 트리에서 이보다 작게 찾기l [i] l [i]l [ i ] 일본r [i] r [i]r [ i ]는 괜찮습니다. 마지막으로l [i] ∗ r [i] l [i] * r [i]l [ i ]∗r [ i ] 가 답이고 AC 코드는 다음과 같습니다.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e4+5;
typedef long long ll;
int n,m,k;
ll a[N],l[N],r[N],tree[N<<2];
vector<ll>v;
int getpos(ll x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void pushup(int i)
{
tree[i]=tree[i<<1]+tree[i<<1|1];
}
void build(int i,int l,int r)
{
if(l==r)
{
tree[i]=0;
return ;
}
int mid=l+r>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
pushup(i);
}
void update(int i,int l,int r,int x,int k)
{
if(l==r)
{
tree[i]+=k;
return ;
}
int mid=l+r>>1;
if(x<=mid) update(i<<1,l,mid,x,k);
else update(i<<1|1,mid+1,r,x,k);
pushup(i);
}
ll query(int i,int l,int r,int m,int n)
{
if(m<=l&&r<=n) return tree[i];
int mid=l+r>>1;
ll ans=0;
if(m<=mid) ans+=query(i<<1,l,mid,m,n);
if(n>mid) ans+=query(i<<1|1,mid+1,r,m,n);
return ans;
}
int main(){
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
n=v.size();
for(int i=1;i<=m;i++){
int pos=getpos(a[i]);
if(pos!=1) l[i]=query(1,1,n,1,pos-1);
update(1,1,n,getpos(a[i]),1);
}
memset(tree,0,sizeof((tree)));
for(int i=m;i>=1;i--){
int pos=getpos(a[i]);
if(pos!=n) r[i]=query(1,1,n,getpos(a[i])+1,n);
update(1,1,n,getpos(a[i]),1);
}
ll ans=0;
for(int i=1;i<=m;i++) ans+=l[i]*r[i];
printf("%lld",ans);
return 0;
}