树状数组

来源:互联网 发布:搞笑淘宝买家秀图对比 编辑:程序博客网 时间:2024/05/02 03:43

树状数组

  树状数组是一个查询和修改复杂度都为log(n)的数据结构,假设数组a[1..n],
  那么查询a[1]+...+a的时间是log级别的,而且是一个在线的数据结构,
  支持随时修改某个元素的值,复杂度也为log级别。
  来观察这个图:
  令这棵树的结点编号为C1,C2...Cn。令每个结点的值为这棵树的值的总和,那么容易发现:
  C1 = A1
  C2 = A1 + A2
  C3 = A3
  C4 = A1 + A2 + A3 + A4
  C5 = A5
  C6 = A5 + A6
  C7 = A7
  C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
  ...
  C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
  这里有一个有趣的性质,下午推了一下发现:
  设节点编号为x,那么这个节点管辖的区间为2^k(其中k为x二进制末尾0的个数)个元素。因为这个区间最后一个元素必然为Ax,
  所以很明显:Cn = A(n – 2^k + 1) + ... + An
  算这个2^k有一个快捷的办法,定义一个函数如下即可:
  int lowbit(int x){
  return x&(x^(x–1));
  }
  当想要查询一个SUM(n)时,可以依据如下算法即可:
  step1: 令sum = 0,转第二步;
  step2: 假如n <= 0,算法结束,返回sum值,否则sum = sum + Cn,转第三步;
  step3: 令n = n – lowbit(n),转第二步。
  可以看出,这个算法就是将这一个个区间的和全部加起来,为什么是效率是log(n)的呢?以下给出证明:
  n = n – lowbit(n)这一步实际上等价于将n的二进制的最后一个1减去。而n的二进制里最多有log(n)个1,所以查询效率是log(n)的。
  那么修改呢,修改一个节点,必须修改其所有祖先,最坏情况下为修改第一个元素,最多有log(n)的祖先。
  所以修改算法如下(给某个结点i加上x):
  step1: 当i > n时,算法结束,否则转第二步;
  step2: Ci = Ci + x, i = i + lowbit(i)转第一步。
  i = i +lowbit(i)这个过程实际上也只是一个把末尾1补为0的过程。
  对于数组求和来说树状数组简直太快了!




以上资料来自baidu百科

PKU有2题树状数组的题


PKU 1195 Mobile phones(2维的~)
http://acm.pku.edu.cn/JudgeOnline/problem?id=1195

PKU 3321 Apple Tree(结合图来求解)
http://acm.pku.edu.cn/JudgeOnline/problem?id=3321

3321需要先o(n)的dfs处理以后才可以使用树状数组
还有就是需要自己写表来构树。。vector=TLE....

lowbit这么写也可以: x&(x^(x-1))
  1. #include<iostream>
  2. #include<vector>
  3. using namespace std;
  4. #define lowbit(x) ((x)&(~(x)+1))
  5. struct Node
  6. {
  7.     int cnt,id;
  8. }node[100001];
  9. int n,ans[1000001],id,C[1000001],sum[1000001],BUF;
  10. struct Next
  11. {
  12.     int next,val;
  13. }next[2000001];
  14. bool flag[1000001];
  15. int dfs(int x)
  16. {
  17.     int i,tmp,cid,nex;
  18.     flag[x]=true;
  19.     tmp=node[x].cnt;
  20.     for(nex=next[x].next;nex!=-1;nex=next[nex].next)
  21.         if(!flag[next[nex].val])tmp+=dfs(next[nex].val);
  22.     ++id;
  23.     node[x].id=id;
  24.     return ans[id]=tmp;
  25. }
  26. int gsum(int x)
  27. {
  28.     int ret=0;
  29.     while(x>0)
  30.     {
  31.         ret+=C[x];
  32.         x-=lowbit(x);
  33.     }
  34.     return ret;
  35. }
  36. void update(int x,int val)
  37. {
  38.     while(x<=n)
  39.     {
  40.         C[x]+=val;
  41.         x+=lowbit(x);
  42.     }
  43. }
  44. int main()
  45. {
  46.     int a,b,i,m,tval,nex;
  47.     char c;
  48.     while(scanf("%d",&n)!=EOF)
  49.     {
  50.         for(i=1;i<=n;i++)node[i].cnt=1;
  51.         memset(ans,0,sizeof(ans));
  52.         memset(flag,false,sizeof(flag));
  53.         for(i=1;i<=n;i++)next[i].next=-1;
  54.         BUF=1000001;
  55.         id=0;
  56.         for(i=1;i<n;i++)
  57.         {
  58.             scanf("%d%d",&a,&b);
  59.             nex=a;
  60.             next[a].val=a;
  61.             while(nex!=-1)
  62.             {
  63.                 if(next[nex].next==-1)break;
  64.                 nex=next[nex].next;
  65.             }
  66.             next[nex].next=++BUF;
  67.             next[BUF].val=b;
  68.             next[BUF].next=-1;
  69.             nex=b;
  70.             next[b].val=b;
  71.             while(nex!=-1)
  72.             {
  73.                 if(next[nex].next==-1)break;
  74.                 nex=next[nex].next;
  75.             }
  76.             next[nex].next=++BUF;
  77.             next[BUF].val=a;
  78.             next[BUF].next=-1;
  79.         }
  80.         dfs(1);
  81.         memset(sum,0,sizeof(sum));
  82.         for(i=1;i<=n;i++)sum[i]=i;
  83.         for(i=1;i<=n;i++)C[i]=sum[i]-sum[i-lowbit(i)];
  84.         scanf("%d%*c",&m);
  85.         while(m--)
  86.         {
  87.             scanf("%c %d%*c",&c,&id);
  88.             if(c=='Q')
  89.             {
  90.                 printf("%d/n",gsum(node[id].id)-gsum(node[id].id-ans[node[id].id]));
  91.             }
  92.             else
  93.             {
  94.                 tval=(node[id].cnt==1?-1:1);
  95.                 node[id].cnt=(node[id].cnt==0?1:0);
  96.                 update(node[id].id,tval);
  97.             }
  98.         }
  99.     }
  100.     return 0;
  101. }

原创粉丝点击