树状数组(二叉索引树)(uva 1428 - Ping pong )
2014-04-11 13:22
323 查看
个人认为树状数组在功能上是RMQ算法的升级版。
树状数组支持以下两种操作:
Add(x,d) : 让Ax增加d;
Query(L,R): 计算A(l)+A(l+1)+A(l+2)+....+A(R);
首先,我们定义lowbit(x)为x的二进制表达式中最右边的1所对应的数值(不是序列号)。比如5的二进制是101,lowbit(5)=1;6的二进制是110,lowbit(6)=2。
如何计算lowbit呢?lowbit(x)=x&(-x);因为在计算机中负数是正数按位取反加1得到的。
变成一棵树:(叫做树状数组的原因吧<_<)
红色节点是我们要存储的,红色节点存储的是红色节点加上前面蓝色节点的和。
比如c8代表的是a1-a8的和,c12代表的是a9-a12的和。(c为辅助数组,a为存储具体数值的数组)
并且每层的lowbit的值是相同的。(觉得网络上的图意思表达的不明显,自己不会用数学绘图软件T-T,就用excel自己做了个,不太好看见谅。)
ci=a(i-lowbit(i)+1)+a(i-lowbit(i)+2)+...a(i);
有了数组c后如何计算前缀和Si呢?顺着节点i往左走,边走边“爬”(注意并不一定沿着树爬),把沿途的ci加起来就行了,如下图计算s11:
修改一个ai,需要更新哪些ci呢?从ci向右走,边走边“爬”,如下图修改a3:
我的模板:
练习题可以做uva 1428 - Ping pong
考虑第i个人当裁判的情况。加上a1到a(i-1)中有ci个比ai小,那么有(i-1)-ci个比ai大;同理,假设a(i+1)到a(n)有di个比ai小,那么就有(n-i)-di个比ai大。此时就有ci(n-i-di)+(i-ci-1)di种比赛。问题就变成求ci和di了。
ok,ci可以这样求,用辅助数组X[j]表示到目前为止,有几个ai与j相等,则ci就是X[1]...X[ai-1]的前缀和了。
时间复杂度为O(n);
我的代码:
如果每个人都能力值不唯一的话(>_>我没有看错题),可以用下面的代码:
树状数组支持以下两种操作:
Add(x,d) : 让Ax增加d;
Query(L,R): 计算A(l)+A(l+1)+A(l+2)+....+A(R);
首先,我们定义lowbit(x)为x的二进制表达式中最右边的1所对应的数值(不是序列号)。比如5的二进制是101,lowbit(5)=1;6的二进制是110,lowbit(6)=2。
如何计算lowbit呢?lowbit(x)=x&(-x);因为在计算机中负数是正数按位取反加1得到的。
变成一棵树:(叫做树状数组的原因吧<_<)
红色节点是我们要存储的,红色节点存储的是红色节点加上前面蓝色节点的和。
比如c8代表的是a1-a8的和,c12代表的是a9-a12的和。(c为辅助数组,a为存储具体数值的数组)
并且每层的lowbit的值是相同的。(觉得网络上的图意思表达的不明显,自己不会用数学绘图软件T-T,就用excel自己做了个,不太好看见谅。)
ci=a(i-lowbit(i)+1)+a(i-lowbit(i)+2)+...a(i);
有了数组c后如何计算前缀和Si呢?顺着节点i往左走,边走边“爬”(注意并不一定沿着树爬),把沿途的ci加起来就行了,如下图计算s11:
修改一个ai,需要更新哪些ci呢?从ci向右走,边走边“爬”,如下图修改a3:
我的模板:
int lowbit(int x){ return x&(-x); } int sum(int x){ int ret=0; while (x>0) { ret+=C[x];x-=lowbit(x); } return ret; } int add(int x,int d){ while (x<=n){ C[x]+=d;x+=lowbit(x); } return 0; } int query(int L,int R){ return sum(R)-sum(L-1); }
练习题可以做uva 1428 - Ping pong
考虑第i个人当裁判的情况。加上a1到a(i-1)中有ci个比ai小,那么有(i-1)-ci个比ai大;同理,假设a(i+1)到a(n)有di个比ai小,那么就有(n-i)-di个比ai大。此时就有ci(n-i-di)+(i-ci-1)di种比赛。问题就变成求ci和di了。
ok,ci可以这样求,用辅助数组X[j]表示到目前为止,有几个ai与j相等,则ci就是X[1]...X[ai-1]的前缀和了。
时间复杂度为O(n);
我的代码:
#include <cstdio> #include <cstring> #include <algorithm> const int maxn =20000; using namespace std; int C[200009],a[maxn],d[maxn],b[maxn],n,maxd; int lowbit(int x){ return x&(-x); } int sum(int x){ int ret=0; while (x>0) { ret+=C[x];x-=lowbit(x); } return ret; } int add(int x,int d){ //printf("%d\n",maxd); while (x<=maxd){ C[x]+=d;x+=lowbit(x); } return 0; } int main (){ int T;scanf("%d",&T); while (T--){ memset(C,0,sizeof(C)); scanf("%d",&n);maxd=0; for (int i=0;i<n;i++){ scanf("%d",&a[i]); maxd=max(maxd,a[i]); } for (int i=0;i<n;i++){ d[i]=sum(a[i]-1); add(a[i],1); } memset(C,0,sizeof(C)); for (int i=n-1;i>=0;i--){ b[i]=sum(a[i]-1); add(a[i],1); } long long ans=0; for (int i=0;i<n;i++){ ans+=d[i]*(n-i-1-b[i])+(i-d[i])*b[i]; } printf("%lld\n",ans); } return 0; }
如果每个人都能力值不唯一的话(>_>我没有看错题),可以用下面的代码:
#include <cstdio> #include <cstring> #include <algorithm> const int maxn =20000; using namespace std; int C[200009],C1[200009],a[maxn],d[maxn],b[maxn],d1[maxn],b1[maxn],n,maxd; int lowbit(int x){ return x&(-x); } int sum(int x){ int ret=0; while (x>0) { ret+=C[x];x-=lowbit(x); } return ret; } int add(int x,int d){ while (x<=maxd){ C[x]+=d;x+=lowbit(x); } return 0; } int sum1(int x){ int ret=0; while (x<maxd+1) { ret+=C1[x];x+=lowbit(x); } return ret; } int add1(int x,int d){ while (x>=1){ C1[x]+=d;x-=lowbit(x); } return 0; } int main (){ int T;scanf("%d",&T); while (T--){ memset(C,0,sizeof(C)); memset(C1,0,sizeof(C1)); scanf("%d",&n);maxd=0; for (int i=0;i<n;i++){ scanf("%d",&a[i]); maxd=max(maxd,a[i]); } for (int i=0;i<n;i++){ add(a[i],1); add1(a[i],1); d[i]=sum(a[i]-1); d1[i]=sum1(a[i]+1); } memset(C,0,sizeof(C)); memset(C1,0,sizeof(C1)); for (int i=n-1;i>=0;i--){ add(a[i],1); add1(a[i],1); b[i]=sum(a[i]-1); b1[i]=sum1(a[i]+1); } long long ans=0; for (int i=0;i<n;i++){ //printf("%d\n",i+1); //printf("左小%d 右小%d\n",d[i],b[i]); //printf("左大%d 右大%d\n",d1[i],b1[i]); ans+=d[i]*b1[i]+d1[i]*b[i]; } printf("%lld\n",ans); } return 0; }
相关文章推荐
- uva 1428 - Ping pong (二叉索引树)
- 【UVA1428】Ping pong
- Uva 1428 Ping pong (树状数组,Fenwick树)
- UVa:1428 Ping pong (树状数组)
- UVALive - 4329 Ping pong 树状数组
- uva1428 Ping pong
- UVA-1428 - Ping pong(树状数组)
- uva 1428 - Ping pong(树状数组)
- UVA 1428 - Ping pong(树状数组)
- UVA 1428 Ping Pong(树状数组)
- [树状数组]Ping Pong, Beijing 2008, Uva1428
- UVa 1428 Ping pong
- 【uva】1428 - Ping pong(树状数组)
- uva 1428 - Ping pong
- Beijing 2008 / UVa 1428 / POJ 3928 / HDU 2492 Ping pong (树状数组)
- uva 1428 - Ping pong(树状数组,4级)
- uva 1428 - Ping pong(树状数组,4级)
- Ping pong UVA - 1428 树状数组
- UVa-1428 - Ping pong
- UVa 1428 - Ping pong