HDU 2492 Ping pong

HDU_2492

    由于N比较大,枚举两个队员并计算其中有多少个裁判是行不通的,不妨换一种思路去枚举裁判,这样对于任意一个裁判而言,不同的比赛场数等于左边小于裁判skill rank的人数乘以右边大于裁判skill rank的人数,再加上右边小于裁判skill rank的人数乘以左边大于裁判skill rank的人数。

    在计算人数的时候,可以维护记录分别记录左右两边各个skill rank的人数的两棵线段树,每当枚举一个裁判时,先将裁判从右边的线段树删去,计算完之后再将裁判添加到左边的线段树中。

#include<stdio.h>
#include<string.h>
#define MAXD 400010
int N, M, a[MAXD], lt[MAXD], rt[MAXD];
void init()
{
int i, j, k;
memset(lt, 0, sizeof(lt));
memset(rt, 0, sizeof(rt));
scanf("%d", &N);
for(i = 0; i < N; i ++)
{
scanf("%d", &a[i]);
rt[a[i] + M] = 1;
}
for(i = M - 1; i > 0; i --)
rt[i] = rt[2 * i] + rt[2 * i + 1];
}
void updatel(int i)
{
for(; i ^ 1; i >>= 1)
lt[i >> 1] = lt[i] + lt[i ^ 1];
}
void updater(int i)
{
for(; i ^ 1; i >>= 1)
rt[i >> 1] = rt[i] + rt[i ^ 1];
}
int countl(int x, int y)
{
int i = M + x - 1, j = M + y + 1, ans = 0;
for(; i ^ j ^ 1; i >>= 1, j >>= 1)
{
if(~i & 1)
ans += lt[i ^ 1];
if(j & 1)
ans += lt[j ^ 1];
}
return ans;
}
int countr(int x, int y)
{
int i = M + x - 1, j = M + y + 1, ans = 0;
for(; i ^ j ^ 1; i >>= 1, j >>= 1)
{
if(~i & 1)
ans += rt[i ^ 1];
if(j & 1)
ans += rt[j ^ 1];
}
return ans;
}
void solve()
{
int i, j, k, t1, t2;
long long int ans = 0;
for(i = 0; i < N; i ++)
{
t1 = t2 = 0;
rt[M + a[i]] = 0;
updater(M + a[i]);
t1 = countl(1, a[i]), t2 = countr(a[i], 100000);
ans = (long long int)t1 * t2 + ans;
t1 = countl(a[i], 100000), t2 = countr(1, a[i]);
ans = (long long int)t1 * t2 + ans;
lt[M + a[i]] = 1;
updatel(M + a[i]);
}
printf("%I64d\n", ans);
}
int main()
{
int t;
for(M = 1; M < 100002; M <<= 1);
scanf("%d", &t);
while(t --)
{
init();
solve();
}
return 0;
}


你可能感兴趣的:(ping)