poj-3928(树状数组)
题目链接:传送门
题意:n个乒乓球运动员要互相练习,都去一个运动员那里比赛,举办训练的运动员不能水平最高或最低。
现在给出n个运动员的水平,求出最终有多少种组合。
思路:先对运动员进行离散化,然后进行比较,第一位和最后一位运动员的不能举行训练,所以跳过,
对剩下的运动员进行查找,有两种情况
(1)这个运动员的前面的人的水平比当前的人低的人数有pr,后面水平比前面高的人有lt个,ans+=pr*lt。
(2)这个运动员的前面的人的水平比当前的人高的人数有pr,后面水平比前面低的人有lt个,ans+=pr*lt。
所以求出最终的人数。
注意:
(1)最终结果很多,ans要用long long类型。
(2)要先对第一名运动员进行update操作。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn = 100100*4; typedef long long LL; int c[maxn],n,b[maxn]; struct Node{ int id,x; }a[maxn]; bool cmp(Node a,Node b) { return a.x<b.x; } int lowbit(int x) { return x&(-x); } void update(int x) { while(x<maxn) { c[x]++; x+=lowbit(x); } } int query(int x) { int sum=0; while(x>0) { sum+=c[x]; x-=lowbit(x); } return sum; } int main(void) { int T,i,j,n; scanf("%d",&T); while(T--) { memset(b,0,sizeof(b)); memset(c,0,sizeof(c)); scanf("%d",&n); for(i=1;i<=n;i++) scanf("%d",&a[i].x),a[i].id=i; sort(a+1,a+n+1,cmp); for(i=1;i<=n;i++) b[a[i].id]=i; LL ans=0,pr,lt; update(b[1]); for(i=2;i<n;i++) { update(b[i]); int tmp=query(b[i]); pr=tmp-1; lt=n-i-b[i]+tmp; ans+=pr*lt; pr=i-tmp; lt=b[i]-tmp; ans+=pr*lt; } printf("%lld\n",ans); } return 0; }