2008 北京区域赛 ping pong // icpc 4329 ping pong
题目: 每两人比赛需要裁判(第三名比赛队员充当),并且裁判的等级在两者之间,并且裁判需要在那两名选手的位置之间,问可以安排多少场这样的比赛。 分析: 树状数组枚举裁判,分别求到左边位置比该队员的等级高的和等级低的选手数目,当求完之后再从左到右分别删除该项后,求到比他等级高的和等级小的,删除操作只需要modify操作时减掉1即可实现。然后根据乘法原理可知用左边的等级高的*右边等级低的+右边等级高的*左边等级低的。 #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int X = 100005; int n,a[X]; long long r[X],l[X]; long long r_max[X],l_max[X]; long long c[X]; int lowbit(int x) { return x & -x; } void modify(int x,int num) { while(x<X) { c[x] += num; x += lowbit(x); } } long long query(int x) { long long ans = 0; while(x>0) { ans += c[x]; x -= lowbit(x); } return ans; } int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); int t; scanf("%d",&t); while(t--) { memset(c,0,sizeof(c)); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); l[i] = query(a[i]); l_max[i] = query(X-1)-l[i]; modify(a[i],1); } for(int i=1;i<=n;i++) { modify(a[i],-1); r[i] = query(a[i]); r_max[i] = query(X-1)-r[i]; } long long ans = 0; for(int i=1;i<=n;i++) ans += l[i]*r_max[i]+r[i]*l_max[i]; cout<<ans<<endl; } return 0; }