您的位置:首页 > 其它

【uva】1428 - Ping pong(树状数组)

2014-07-30 00:06 387 查看
周五需要检测 树状数组以及线段树,这几天猛练一下,晚上看了一下二叉索引树,感觉还可以理解,不过A题的还是很有难度的。

题意给的很明显了,给一个位置i,求这个位置左边和右边比它小的数的个数(求出小的,求大的用减就可以了,因为a[i]的值都不重复.

我们从左往右检查,我们用一个数组vis[i]记录i值是否出现过(出现过为1,没出现为0),那么遍历到a[i]的时候我们只需要求 vis[1] + vis[2] + ……+vis[a[i] - 1],这样每次我们都需要花大量时间进行查询,其次,加入你使用C[i] 代表 vis[1] + vis[2] + …… +vis[i],那么,每次更行a[i],你都需要更新C[j] ( j > a[i]),非常耗费时间。因此使用上了树状数组。

如果进行查询操作,求vis[1] + vis[2] + vis[x];

int Sum(int x){    /*求和的话向左边走*/
    int ans = 0;
    while(x > 0){
        ans += C[x];
        x -= lowbit(x);
    }
    return ans;
}


如果进行插入,该表vis的值

int Add(int x,int d){
    while(x < MAXD){
        C[x] += d;
        x += lowbit(x);
    }
}


此外,lowbit(x) = x & -x;

这题经过计算数据范围需要使用long long 表示

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define MAXD 100000 + 10
typedef long long LL;
int array[MAXD];
int C[MAXD];
int lowbit(int x){
return x & -x;
}
int Sum(int x){ /*求和的话向左边走*/ int ans = 0; while(x > 0){ ans += C[x]; x -= lowbit(x); } return ans; }
int Add(int x,int d){ while(x < MAXD){ C[x] += d; x += lowbit(x); } }
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;
int vis[MAXD]; /*记录i是否存在*/
int c[MAXD],d[MAXD];
memset(vis,0,sizeof(vis));
memset(C,0,sizeof(C));
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++)
scanf("%d",&array[i]);
for(int i = 1 ; i <= n ; i++){ /*左边比a[i]小的数个数*/
int t = array[i];
if(!vis[t]){
vis[t] = 1;
Add(t,1);
}
c[i] = Sum(t) - 1;
}
memset(C,0,sizeof(C));
memset(vis,0,sizeof(vis));
for(int i = n ; i >= 1; i--){ /*右边比a[i]小的数个数*/
int t = array[i];
if(!vis[t]){
vis[t] = 1;
Add(t,1);
}
d[i] = Sum(t) - 1;
}
LL ans = 0;
for(int i = 1 ; i <= n ; i++){
ans = ans + c[i] * (n - i - d[i]) + (i - 1 - c[i]) * d[i];
}
printf("%lld\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: