【洛谷P1637】三元上升子序列

题目大意:给定一个长度为 N 的序列,求有多少个三元组满足 \(i<j<k,a_i<a_j<a_k\)

题解:这是一类二维偏序问题,与逆序对问题类似。
对于序列中每个点来说,用树状数组统计左边有多少个值比他小,右边有多少个值比他大,最后扫一遍数组计算答案贡献即可。

代码如下

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int dx[]={0,1,0,-1};
const int dy[]={1,0,-1,0};
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const int maxn=3e4+10;
const double eps=1e-6;
inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
inline ll sqr(ll x){return x*x;}
inline ll read(){
	ll x=0,f=1;char ch;
	do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
	do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
	return f*x;
}
/*--------------------------------------------------------*/

int n;
ll a[maxn],le[maxn],la[maxn];
ll d[maxn],tot;
ll bit[maxn];
inline void modify(int pos){
	for(int i=pos;i<=n;i+=i&-i)bit[i]++;
}
inline ll query(int pos){
	ll ret=0;
	for(int i=pos;i;i-=i&-i)ret+=bit[i];
	return ret;
}

void read_and_parse(){
	n=read();
	for(int i=1;i<=n;i++)a[i]=d[i]=read();
	sort(d+1,d+n+1);
	tot=unique(d+1,d+n+1)-d-1;
	for(int i=1;i<=n;i++)a[i]=lower_bound(d+1,d+tot+1,a[i])-d;
}

void solve(){
	for(int i=1;i<=n;i++){
		le[i]=query(a[i]-1);
		modify(a[i]);
	}
	memset(bit,0,sizeof(bit));
	for(int i=n;i>=1;i--){
		la[i]=query(n)-query(a[i]);
		modify(a[i]);
	}
	ll ans=0;
	for(int i=1;i<=n;i++)ans+=le[i]*la[i];
	printf("%lld\n",ans);
}

int main(){
	read_and_parse();
	solve();
	return 0;
}

posted @ 2019-04-03 15:10  shellpicker  阅读(270)  评论(0编辑  收藏  举报