zoukankan      html  css  js  c++  java
  • 树状树组

    这里丢一篇很好的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 }
     
    为何要逼自己长大,去闯不该闯的荒唐
  • 相关阅读:
    (转)STMFD和LDMFD指令个人理解分析
    [原创] linux下的串口调试工具
    详解Makefile 函数的语法与使用 (转)
    sed命令详解(转)
    [转]QT4解决中文乱码(tr的使用 | QTextCodec)
    新型的按键扫描程序,仅三行程序(转)
    VS2010旗舰版不能安装Silverlight4_Tools的解决方案
    ASP.NET MVC3+EF4+Oracle入门实例(六)
    一个ASP.NET文件下载类
    项目管理实践【四】自动编译和发布网站【Using Visual Studio with Source Control System to build and publish website automatically】
  • 原文地址:https://www.cnblogs.com/zjzjzj/p/10778816.html
Copyright © 2011-2022 走看看