数据结构颓废计划I-树状数组复习

本文介绍了树状数组的基本原理及其在区间求和问题中的应用,并通过两个实例详细展示了如何利用树状数组解决实际问题。

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

Simple but useful.

对于满足区间加法/减法性质的元素所组成的序列,可以使用树状数组来维护。

原理

一些约定

Ai 为原序列
Fenwick_Tree[i]为树状数组

lowbit

对于一个有符号类型的下标,我们定义:

lowbit(x)=x&(-x)

lowbit(x)的数学意义在于求出x的二进制表示的从右往左第一个1的位置。在树状数组中,对于Fenwick_Tree[x],它一定等于:

i=xlowbit(x)xAi

区间求和

那么对于 [1,x] 的区间求和问题,我们只需要反复执行上一过程,即可求得。若要求 [x,y] 的区间和,那么可以由:

i=1yAii=1x1Ai=i=xyAi

如上的明显的性质,来求给定区间的区间和。

单点修改

也很明显。这里不讨论。

例题

CodeVS1080 线段树练习1

题面
题解

拒绝解释

#include "iostream"
#include "cstring"
using namespace std;
int c[1000001];

    int N,T;
inline int lowbit(int x)
  {
    return x&(-x);
  }
int sum(int n)
 {
    int Ans=0;
    while(n>0)
     {
        Ans+=c[n];
        n-=lowbit(n);
      }
    return Ans;
 }
void change(int i,int x)
{
  while(i<=N)
     {
         c[i]=c[i]+x;
         i=i+lowbit(i);
     }
}
int main()
 {
    cin >> N;
    memset(c,0,sizeof(c));
    for ( int i=1;i<=N;i++)
     {
        cin >> T;
        change(i,T);
      }
    cin >> T;
    int l,r,op,x,a;
    for ( int i=1;i<=T;i++)
     {
         cin >> op;
         if(op==1)
           {
              cin >> x >> a;
              change(x,a);
           }
         if(op==2)
           {
              cin >> l >> r;
              cout << sum(r) - sum(l-1) << endl;
           }
     }
    return 0;
 }

URAL1028 STAR

题面
题解

经典老题

我们将星星按横坐标排序,每次统计高度小于等于当前星星的星星个数,然后再单点修改一下这个高度对应的所有的Fenwick_Tree的值即可, O( N log N ) 左右。

#include <cstdio>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>
using namespace std;
int N;
int a[32002];
int lowbit(int x)
{
 return x^(x&(x-1));
}

void update( int i )
 {
    while(i<=32001)
     {
        a[i]++;
        i+=lowbit(i);
      }
    return ;
 }
int query( int i )
 {
    int Ans=0;
    while(i>0)
     {
        Ans+=a[i];
        i-=lowbit(i);
      }
    return Ans;
 }
int in()
 {
    char ch=getchar();
    int Ans=0;
    while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') 
     {
        Ans=Ans*10+ch-'0';
        ch=getchar();
      }
    return Ans;
 }
pair < int , int > stars[15001];
int level[15001];
int main()
 {
    N=in(); 
    for ( int i=1;i<=N;i++)
      {
        stars[i].first=in();
        stars[i].second=in();
      }
    sort(stars+1,stars+1+N);
    memset(a,0,sizeof(a));
    memset(level,0,sizeof(level));
    for ( int i=1;i<=N;i++)
     {
         level[query(stars[i].second+1)]++;
         update(stars[i].second+1);
     }
    for ( int i=0;i<=N-1;i++)
      printf("%d\n",level[i]);
    return 0;
  } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值