【CH4201】楼兰图腾

题目大意:给定一个长度为 N 的序列,从序列中任意挑出三个数,求满足中间的数字值最小(最大)有多少种情况。

题解:建立在值域上的树状数组,从左到右扫描一遍序列,统计出每个点左边有多少个数大于(小于)该点的值,再从右到左扫描一遍序列,统计出每个点右边有多少个数大于(小于)自己,最后计算答案贡献即可。

代码如下

#include <bits/stdc++.h>
#define cls(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&-x
#define all(x) x.begin(),x.end()
using namespace std;
const int maxn=2e5+10;

inline int read(){
	int 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,a[maxn],bit[maxn],left1[maxn],left2[maxn],right1[maxn],right2[maxn];
long long ans1,ans2;

void read_and_parse(){
	n=read();
	for(int i=1;i<=n;i++)a[i]=read();
}

inline void modify(int x,int val){
	for(int i=x;i<=n;i+=lowbit(i))bit[i]+=val;
}
inline int query(int x){
	int ans=0;
	for(int i=x;i;i-=lowbit(i))ans+=bit[i];
	return ans;
}

void solve(){
	for(int i=1;i<=n;i++){
		left1[i]=query(a[i]-1);
		left2[i]=query(n)-query(a[i]);
		modify(a[i],1);
	}
	cls(bit,0);
	for(int i=n;i>=1;i--){
		right1[i]=query(a[i]-1);
		right2[i]=query(n)-query(a[i]);
		modify(a[i],1);
	}
	for(int i=1;i<=n;i++)ans1+=(long long)left2[i]*right2[i],ans2+=(long long)left1[i]*right1[i];
	printf("%lld %lld\n",ans1,ans2);
}

int main(){
	read_and_parse();
	solve();
	return 0;
} 
posted @ 2018-12-11 11:59  shellpicker  阅读(697)  评论(0编辑  收藏  举报