UVA1428 Ping pong(树状数组)

UVA1428 Ping pong(树状数组)

传送门

思路:权值树状数组。

考虑枚举每个位置作为裁判对答案的贡献。

显然有两种情况:

1. a [ l ] < a [ i ] < a [ r ] , l < i < r 1.a[l]<a[i]<a[r],l<i<r

2. a [ l ] > a [ i ] > a [ r ] , l < i < r 2.a[l]>a[i]>a[r],l<i<r

因为每个数互异。

根据乘法原理所以贡献为: l l o w e r [ i ] × r u p p e r [ i ] + l u p p e r [ i ] × r l o w e r [ i ] l_{lower}[i]\times r_{upper}[i]+l_{upper}[i]\times r_{lower}[i]

且题目数据 a [ i ] 1 e 5 a[i]\leq 1e5 .所以可以用权值树状数组来维护。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e4+5,M=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first 
#define se second
int t,n,a[N],tr[M];
int l_up[N],l_low[N],r_up[N],r_low[N];
#define lowbit(x) x&(-x)
void update(int x,int k){
	while(x<=1e5){
		tr[x]+=k;
		x+=lowbit(x);
	}
}
ll query(int x){
	ll ans=0;
	while(x){
		ans+=tr[x];
		x-=lowbit(x);
	}
	return ans;
}
int main(){	
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			l_up[i]=query(a[i]);
			l_low[i]=i-l_up[i]-1;
			update(a[i],1); 
		}
		for(int i=1;i<=1e5;i++)
			tr[i]=0;
		ll ans=0;
		for(int i=n;i>=1;i--){
			r_up[i]=query(a[i]);
			r_low[i]=n-i-r_up[i];
			ans+=1LL*l_up[i]*r_low[i];
			ans+=1LL*l_low[i]*r_up[i];
			update(a[i],1);
		}
		for(int i=1;i<=1e5;i++)
			tr[i]=0;
		printf("%lld\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45750972/article/details/106983616