树状数组(单点更新,区间查询;区间更新,单点查询;二维数组的树状数组实现)

39 篇文章 0 订阅
25 篇文章 1 订阅

 1)lowbit(x)=x & (-x)
    将x转换为二进制,则lowbit(x)就是右边第一个'1'号位表示的位权
    lowbit 可以理解为能整除x的最大的2的幂次

///c[x]存储a[x](含x号位)前Lowbit(x)个数
///c[x]=a[x-lowbit(x)+1]+...+a[x];
///-> sum(1,x)=a[1]+a[2]+...+a[x]=
///            a[1]+...+a[x-lowbit(x)]+a[x-lowbit[x]+1]+...+a[x]
///           =a[1]+...+a[x-lowbit[x]]+c[x];
///->     sum(1,x)=sum(1,x-lowbit(x))+c[x];

/**
    1)lowbit(x)=x & (-x)
    将x转换为二进制,则lowbit(x)就是右边第一个'1'号位表示的位权
    lowbit 可以理解为能整除x的最大的2的幂次
*/

/**
#include <iostream>

using namespace std;
void update(int x,int v);
int getsum(int x);
#define lowbit(x) ((x)&(-x))
const int maxn=1001;
int c[maxn];
int main()
{
    memset(c,0,sizeof(c));
    int n,x;
    cin >> n;
    for(int i=0;i<n;++i)
    {
        cin >> x;
        update(x,1);
        cout << "append " << getsum(x-1) << endl;      //a[i]左边比a[i]小的元素个数
        cout << "append " << getsum(maxn)-getsum(x) << endl;    //a[i]左边比a[i]大的元素个数
    }

    ///以下的代码是求a[i]右边比它小或大的个数
    cin >> n;
    int a[n];
    for(int i=0;i<n;++i)
        cin >> a[i];

    for(int i=n-1;i>=0;--i)
    {
        update(a[i],1);
        cout << "append " << getsum(a[i]-1) << endl;         //a[i]右边比a[i]小的元素个数
        cout << "append " << getsum(maxn)-getsum(a[i]) << endl;    //a[i]右边比a[i]大的元素个数
    }

    return 0;
}

///c[x]存储a[x](含x号位)前Lowbit(x)个数
///c[x]=a[x-lowbit(x)+1]+...+a[x];
///-> sum(1,x)=a[1]+a[2]+...+a[x]=
///            a[1]+...+a[x-lowbit(x)]+a[x-lowbit[x]+1]+...+a[x]
///           =a[1]+...+a[x-lowbit[x]]+c[x];
///->     sum(1,x)=sum(1,x-lowbit(x))+c[x];
int getsum(int x)
{
    int sum=0;
    while(x>0)
    {
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}

void update(int x,int v)
{
    for(int i=x;i<maxn;i+=lowbit(i))
        c[i]+=v;
}
*/

2) 当a[i]太大以至于开不了这么大的数组的是时候,可以将值存到
    结构体中,将他们的大小序号与结构体数组下标对应起来
    lowbit(x)=x&(-x)
    将x转换为二进制,则lowbit(x)就是右边第一个'1'号位表示的位权
    lowbit 可以理解为能整除x的最大的2的幂次
    单点更新,区间查询

/**
    2) 当a[i]太大以至于开不了这么大的数组的是时候,可以将值存到
    结构体中,将他们的大小序号与结构体数组下标对应起来
    lowbit(x)=x&(-x)
    将x转换为二进制,则lowbit(x)就是右边第一个'1'号位表示的位权
    lowbit 可以理解为能整除x的最大的2的幂次
    单点更新,区间查询
*/

/**
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

void update(int x,int v);
int getsum(int x);
int find_kth_element(int k);//寻找序列中第k大的数
#define lowbit(x) ((x)&(-x))
const int maxn=1001;
struct Node
{
    int val;
    int pos;
};
bool cmp(Node a,Node b)
{
    return a.val<b.val;
}
int c[maxn];
int main()
{
    memset(c,0,sizeof(c));
    int n;
    cin >> n;
    Node temp[n];
    int a[n];
    for(int i=0;i<n;++i)
    {
        cin >> temp[i].val;
        temp[i].pos=i;
    }
    sort(temp,temp+n,cmp);
    for(int i=0;i<n;++i)
    {
        if(i==0||temp[i].val!=temp[i-1].val)
            a[temp[i].pos]=i+1; //第一个数必须从1开始存储,因为在调用update函数时,会进行loebit操作
        else                    //而lowbit(0)是等于0,就会进入死循环
            a[temp[i].pos]=a[temp[i-1].pos];
    }
    for(int i=0;i<n;++i)    //必须先将元素存到数组c中,才能查询序列的排名
        update(a[i],1);     //因为查询排名也是要调用getsum,而getsum函数也是需要数组c的

    cout << find_kth_element(n-2) << endl;
    cout << temp[find_kth_element(n-2)-1].val << endl;
    return 0;
}

//c[x]存储a[x](含x号位)前Lowbit(x)个数
//c[x]=a[x-lowbit(x)+1]+...+a[x];
//-> sum(1,x)=a[1]+a[2]+...+a[x]=
//            a[1]+...+a[x-lowbit(x)]+a[x-lowbit[x]+1]+...+a[x]
//           =a[1]+...+a[x-lowbit[x]]+c[x];
//->     sum(1,x)=sum(1,x-lowbit(x))+c[x];
int getsum(int x)   //返回前x个数的和
{
    int sum=0;
    while(x>0)
    {
        sum+=c[x];
        x-=lowbit(x);
    }
    return sum;
}

void update(int x,int v)    //第x个数加上v
{
    for(int i=x;i<maxn;i+=lowbit(i))
    {
        c[i]+=v;
    }
}

int find_kth_element(int k)
{
    int mid,l=1,r=maxn;
    while(l<r)
    {
        mid=(l+r)/2;
        if(getsum(mid)>=k)
            r=mid;
        else
            l=mid+1;
    }
    return l;
}
*/

3) lowbit(x)=x&(-x)
    将x转换为二进制,则lowbit(x)就是右边第一个'1'号位表示的位权
    lowbit 可以理解为能整除x的最大的2的幂次
    单点更新,区间查询
    返回二维矩阵a[1][1]到a[i][j](一个子矩阵)的和


/**

    3) lowbit(x)=x&(-x)
    将x转换为二进制,则lowbit(x)就是右边第一个'1'号位表示的位权
    lowbit 可以理解为能整除x的最大的2的幂次
    单点更新,区间查询
    返回二维矩阵a[1][1]到a[i][j](一个子矩阵)的和
*/

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

void update(int x,int y,int v);
int getsum(int x,int y);    //返回二维矩阵a[1][1]到a[i][j]的和
#define lowbit(x) ((x)&(-x))

const int maxn=1001;
int c[maxn][maxn];

int main()
{
    memset(c,0,sizeof(c));
    int m,n;
    cin >> m >> n;
    cout << "输入 " << m << "行" << n << "列的矩阵\n";
    int a[m][n];
    for(int i=1;i<=m;++i)
        for(int j=1;j<=n;++j)
        {
            cin >> a[i][j];
            update(i,j,a[i][j]);
        }

    cout << getsum(m-1,n-1) << endl;
    return 0;
}

int getsum(int x,int y)   //返回二维矩阵a[1][1]到a[i][j]的和
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
        for(int j=y;j>0;j-=lowbit(j))
            sum+=c[i][j];
    return sum;
}

void update(int x,int y,int v)    //包含a[i][j]的矩阵,数组c都加上v
{
    for(int i=x;i<maxn;i+=lowbit(i))
        for(int j=y;j<maxn;j+=lowbit(j))
            c[i][j]+=v;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值