一二维树状数组模板

本文对比了线段树和树状数组的特点及适用场景。树状数组适用于单个元素频繁修改并求区间和的情况,编程和运行效率高;线段树则适用于区间统计问题,能高效处理区间动态修改与查询。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

具体参考: http://poj.org/summerschool/1_interval_tree.pdf

一直没有搞清 线段树和树状数组的区别及用途,下面从该讲义中摘录:

树状数组:适合单个元素经常修改而且还反复要求部分的区间的和的情况。上述问题虽然也可以用线段树解决,但是用树状数组来做,编程效率和程序运行效率都更高。上述问题虽然也可以用线段树解决,但是用树状数组来做,编程效率和程序运行效率都更高如果每次要修改的不是单个元素,而是一个区间,那就不能用树状数组了(效率过低)。二维树状数组用于快速求数字子矩阵的和。

线段树:是一棵二叉树,树中的每一个结点表示了一个区间[a,b]。a,b通常是整数。每一个叶子节点表示了一个单位区间。对于每一个非叶结点所表示的结点[a,b],其左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2,b](除法去尾取整)。线段树的深度不超过logL(L是最长区间的长度)。线段树把区间上的任意一条线段都分成不超过2logL条线段。线段树适用于和区间统计有关的问题。比如某些数据可以按区间进行划分,按区间动态进行修改,而且还需要按区间多次进行查询,那么使用线段树可以达到较快查询速度。


树状数组

先dfs()给各节点重新编号,申请空间用临街表存储树。

再可以采用树状数组来修改、求和等操作

先初始化为0,再逐个插入每个节点的权来完成初始化

#define N 10000

int in[N];

int Lowbit(int t)
{    return t & ( t ^ ( t - 1 ) ); }

//求前end项和

int Sum(int end)
{
     int sum = 0;
     while(end > 0)
     {
         sum += in[end];
         end -= Lowbit(end);
     }
     return sum;
}

//对某个元素进行加法操作:
void plus(int pos , int num)
{
     while(pos <= N) //sizeof(in)
     {
           in[pos] += num;
           pos += Lowbit(pos);
     }
}

也可以直接模拟建树,应申请空间再进行(不过这个更适合用来做线段树)。

Node *maketree(int l,int r)

{

    Node *root= &pMem[nIndex++];

    root->l=l;

    root->r=r;

    root->sum=r-l+1;

    if(l==r)return root;

    int mid=(l+r)/2;

    root->lc=maketree(l,mid);

    root->rc=maketree(mid+1,r);

    return root;

}

void change(Node *root,int x,int c)

{

    root->sum+=c;

    if(root->l==root->r)

        return;

    int mid=(root->l+root->r)/2;

    if(mid>=x) change(root->lc,x,c);

    else change(root->rc,x,c);

}

int query(Node *root,int l,int r)

{

    if(root->l==l&&root->r==r)

        return root->sum;

    int mid=(root->l+root->r)/2;

    if(r<=mid) return query(root->lc,l,r);

    else if(l>mid) return query(root->rc,l,r);

    else return query(root->lc,l,mid)+query(root->rc,mid+1,r);

}

二维树状数组

下表均是从1开始,num为规模Getsum(r+1,t+1)+Getsum(l,b)-Getsum(r+1,b)-Getsum(l,t+1)为从l+1行到r+1行,b+1列到t+1列的和:

int c[MAXNUM][MAXNUM];

int Lowbit(int m)

{

return m&(-m);

}

int Getsum(int i,int j)

{

int tempj,sum=0;

while(i>0){

   tempj = j;

   while(tempj>0){

    sum += c[i][tempj];

    tempj -= Lowbit(tempj);

   }

   i -= Lowbit(i);

}

return sum;

}

void Inc(int i,int j,int m,int num) //(i,j)增加m

{

int tempj;

while(i<=num){

   tempj = j;

   while(tempj<=num){

    c[i][tempj] += m;

    tempj += Lowbit(tempj);

   }

   i += Lowbit(i);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值