您的位置:首页 > 其它

ZOJ2492 ping pong(树状数组BIT)

2016-04-30 17:22 260 查看
C. Ping pong

Time Limit: 1000msMemory Limit: 32768KB 64-bit integer IO format: %lld Java class name: Main

Submit Status PID: 2394

N(3<=N<=20000) ping pong players live along a west-east street(consider the street as a line segment).

Each player has a unique skill rank. To improve their skill rank, they often compete with each other. If two players want to compete, they must choose a referee among other ping pong players and hold the game in the referee’s house. For some reason, the contestants can’t choose a referee whose skill rank is higher or lower than both of theirs.

The contestants have to walk to the referee’s house, and because they are lazy, they want to make their total walking distance no more than the distance between their houses. Of course all players live in different houses and the position of their houses are all different. If the referee or any of the two contestants is different, we call two games different. Now is the problem: how many different games can be held in this ping pong street?

Input

The first line of the input contains an integer T(1<=T<=20), indicating the number of test cases, followed by T lines each of which describes a test case.

Every test case consists of N + 1 integers. The first integer is N, the number of players. Then N distinct integers a1, a2 … aN follow, indicating the skill rank of each player, in the order of west to east. (1 <= ai <= 100000, i = 1 … N).

Output

For each test case, output a single line contains an integer, the total number of different games.

Sample Input

1

3 1 2 3

Sample Output

1

题意:

一些乒乓球员从左到右住在一条街上,每个球员的房子从1到n有门牌号,同时每个球员有一个rank值。然后球员之间想要打一场训练赛,并且需要找另一个球员当裁判。要求裁判的rank值不能大于或者小于这两个比赛的球员,并且裁判的门牌号必须在两个球员门牌号之间。求这样的训练赛一共能有多少场不同的训练赛?(只要裁判或者球员中有一个人不同那么这场训练赛酒视为不同的)

解析:

我们以裁判为参照点,如果第x个人为裁判,那么以他为裁判的场数共有lmin(x)*rmax(x)+lmax*rmin(x).lmin表示他左边的rank值比他小的总人数。rmax表示他的右边rank值比他大的总人数。

所以ans=∑(rmax(x)+lmax*rmin(x))(1≤x≤n)

那么,问题就转化为,对于每一个x如果求他左右比他大和比他小的人数。我们注意到ai≤100000 而且每一个rank值各不相同。所以可以开一个100000的数组来记录ai这个值有几个,然后区间求和,就能知道rank小于他和大于他的一共有多少人了。

详情见代码:(唉,当时写wa了,感觉明明可以A,,,后来想了下是不是先更新再询问……但是觉得既然值各不相同应该是不影响的啊。。。。然后我才发现= =应该所有lmax类的数组都改成long long就过了……mdzz)

//  Created by ZYD in 2015.
//  Copyright (c) 2015 ZYD. All rights reserved.
//

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <climits>
#include <string>
#include <vector>
#include <cmath>
#include <stack>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define Size 100000
#define ll long long
#define mk make_pair
#define pb push_back
#define mem(array) memset(array,0,sizeof(array))
typedef pair<int,int> P;
int n,T;
long long sum;
int ad[105000],a[105000];
long long lmax[105000],lmin[105000],rmax[105000],rmin[105000];
int lowbit(int k){
return k&(-k);
}
void add(int k,int c){
while(k<=100000){
ad[k]+=c;
k+=k&(-k);
}
}
int ask(int k){
int sum=0;
while(k>0){
sum+=ad[k];
k-=(k)&(-k);
}
return sum;
}
int main()
{
freopen("in.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d",&n);
mem(ad);
sum=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);

}
for(int i=1;i<=n;i++){
lmax[i]=i-1-ask(a[i]); //左边大于a[i]
lmin[i]=ask(a[i]-1);//左边小于a[i]
add(a[i],1);
}
mem(ad);
// for(int i=1;i<=n;i++)cout<<a[i];
for(int i=n;i>=1;i--){
rmax[i]=n-i-ask(a[i]); //右边大于a[i]
rmin[i]=ask(a[i]-1);//右边小于a[i]
add(a[i],1);
}
for(int i=1;i<=n;i++){
sum+=(long long )lmin[i]*rmax[i];
sum+=(long long)lmax[i]*rmin[i];
}
cout<<sum<<endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: