树状树组

这里丢一篇很好的blogs

https://www.cnblogs.com/hsd-/p/6139376.html

其实树状数组的是实现是根据二进制的

主要的函数有这三个

int lowbit(int x)
{
    return x&(-x);
}

这个是返回原数上去除末尾一个1的数

such as 

  1. t=6(0110)
  2. -t=-6=(1001+1)=(1010)
  3. t&(-t)=(0010)=2 得到这个有什么用呢,继续看
    现在定义每一列的顶端结点C[]数组 
   如下图
 
 
   C[i]代表 子树的叶子结点的权值之和// 这里以求和举例
   如图可以知道
   C[1]=A[1];
   C[2]=A[1]+A[2];
   C[3]=A[3];
   C[4]=A[1]+A[2]+A[3]+A[4];
   C[5]=A[5];
   C[6]=A[5]+A[6];
   C[7]=A[7];
   C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];
将C[]数组的结点序号转化为二进制
1=(001)      C[1]=A[1];
2=(010)      C[2]=A[1]+A[2];
3=(011)      C[3]=A[3];
4=(100)      C[4]=A[1]+A[2]+A[3]+A[4];
5=(101)      C[5]=A[5];
6=(110)      C[6]=A[5]+A[6];
7=(111)      C[7]=A[7];
8=(1000)    C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];
对照式子可以发现  C[i]=A[i-2^k+1]+A[i-2^k+2]+......A[i]; (k为i的二进制中从最低位到高位连续零的长度)例如i=8时,k=3; 
举个例子 i=7;
sum[7]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7] ;   //前i项和
C[4]=A[1]+A[2]+A[3]+A[4];   C[6]=A[5]+A[6];   C[7]=A[7];
可以推出:   sum[7]=C[4]+C[6]+C[7];
序号写为二进制: sum[(111)]=C[(100)]+C[(110)]+C[(111)];
 
再举个例子 i=5
sum[7]=A[1]+A[2]+A[3]+A[4]+A[5] ;   前i项和
C[4]=A[1]+A[2]+A[3]+A[4];   C[5]=A[5];
可以推出:   sum[5]=C[4]+C[5];
序号写为二进制: sum[(101)]=C[(100)]+C[(101)];

所以说我们可以通过对i加减lowbit(i),就能实现得到111 110 100 000这样的数

int add(int i,int x)
{
    while (i<=n)
    {
        c[i]+=x;
        i+=lowbit(i);
    }
}

这个呢是树状数组实现单点修改

 1 int sum(int i)
 2 {
 3     int res=0;
 4     while (i>=1)
 5     {
 6         res+=c[i];
 7         i-=lowbit(i);
 8     }
 9     return res;
10 }

这个是实现区间求和查询跟上面的是一样的意识

 

 

 

1.树状数组求逆序对

#include<iostream>
#include<algorithm>
using namespace std;
struct sb
{
    int z,num;
}t[1001];
int c[1001],n;
bool cmp(sb a,sb b)
{
    return a.z<b.z?true:false;
}
int lowbit(int x)
{
    return x&(-x);
}
int add(int i,int x)
{
    while (i<=n)
    {
        c[i]+=x;
        i+=lowbit(i);
    }
}
int sum(int i)
{
    int res=0;
    while (i>=1)
    {
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}
int main ()
{
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        cin>>t[i].z;
        t[i].num=i;
    }
    sort(t+1,t+1+n,cmp);
    int ans=0;
    for (int i=1;i<=n;i++)
    {
        add(t[i].num,1);
        ans+=i-sum(t[i].num);
    }
    cout<<ans;
} 

2.树状数组优化最长上升下降序列
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int a[100001];
 6 struct sb
 7 {
 8     int num,val;
 9 }b[100001];
10 int n,t[100001*4];
11 bool cmp (sb a,sb b) { return a.val<b.val?true:false; }
12 int lowbit(int x) { return x&(-x); }
13 void add(int i,int k)
14 {
15     while (i<=n)
16     {
17         t[i]=max(t[i],k);
18         i+=lowbit(i);
19     }
20  } 
21 int find(int i)
22 {
23     int ans=-1e9;
24     while (i)
25     {
26         ans=max(ans,t[i]);
27         i-=lowbit(i);
28     }
29     return ans;
30 }
31 int main ()
32 {
33     int ans=0;
34     cin>>n;
35     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
36     for (int j=1;j<=n;j++) scanf("%d",&b[j].val),b[j].num=j;
37     sort(b+1,b+1+n,cmp);
38     for (int i=1;i<=n;i++) a[i]=b[a[i]].num;
39     for (int i=n;i>=1;i--)
40     {
41         int nt=find(a[i]);
42         add(a[i],++nt);
43         ans=max(nt,ans);
44     }
45     cout<<ans;
46 }

  树状树,区间修改单点查询,差分数组

 1 #include<iostream>
 2 using namespace std;
 3 int a[500001],b[500001],t[1000000];
 4 int n,m;
 5 int lowbit(int x){return x&(-x);}
 6 void add(int i,int k){for (i;i<=n;i+=lowbit(i)) t[i]+=k;}
 7 int get(int i,int ans){for (i;i;i-=lowbit(i)) ans+=t[i]; return ans;}
 8 int main ()
 9 {
10     cin>>n>>m;
11     for (int i=1;i<=n;i++)
12        cin>>a[i],b[i]=a[i]-a[i-1],add(i,b[i]);
13     for (int i=1,op,x,y,z;i<=m;i++)
14     {
15         cin>>op;
16         if (op==1)
17         {
18             cin>>x>>y>>z;
19             add(x,z);
20             add(y+1,-z); 
21         }
22         else
23         {
24             cin>>x;
25             cout<<get(x,0)<<endl; 
26         }
27     } 
28     
29 }

 

 
posted @ 2019-04-27 15:07  Melted_czj  阅读(176)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色