树状数组模板

本文介绍了树状数组在解决特定类型问题中的应用,包括一维和二维情况下的更新与查询操作。通过两个具体实例——敌兵布阵问题及矩阵值查询问题,详细展示了树状数组的实现方式和优势。

假设有一列数{Ai}(1<=i<=n),支持如下两种操作
•1. 将Ai的值加D。
•2. 输出Ai+Ai+1+…+Aj (1<=i<=j<=n)
树状数组是一种特殊的数据结构,这种数据结构的时空复杂度和线段树相似,但是它的系数要小得多
HDU 1166 敌兵布阵

题目: A国在海岸线沿直线布置了N个工兵营地。由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视。

敌兵营地的人数经常变动,大boss每次询问的段都不一样,所以小兵不得不每次都一个一个营地的去数,很快就精疲力尽了

小兵很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?

段都不一样,所以小兵不得不每次都一个一个营地的去数,很快就精疲力尽了

小兵很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?

#include<stdio.h>
#include<string.h>
int c[50005],n;
int lowbit(int x)
{
    return x&(-x);
}
void add(int i, int val)
{
    while(i<=n)
    {
        c[i]+=val;
        i+=lowbit(i);
    }
}
void sub(int i, int val)
{
    while(i<=n)
    {
        c[i]-=val;
        i+=lowbit(i);
    }
}
int sum(int i)
{
    int s=0;
    while(i>0)
    {
        s+=c[i];
        i-=lowbit(i);
    }
    return s;
}
int main()
{
    int T, a, b, i, d, time=0;
    char ch[10];
    scanf("%d", &T);
    while(T--)
    {
        memset(c,0,sizeof(c));
        scanf("%d",&n);
        for(i=1; i<=n; i++)
        {
            scanf("%d",&d);
            add(i,d);
        }
        while(scanf("%s",ch)&&strcmp(ch,"End")!=0)
        {
            scanf("%d %d",&a,&b);
            if(ch[0]=='Q')
                printf("%d\n",sum(b)-sum(a-1));
            if(ch[0]=='A')
                add(a, b);
            if(ch[0]=='S')
                sub(a, b);
        }
    }
    return 0;
}

二位树状数组

HLg 2046最后的题目八个字

题目:

给出N*N的矩阵A,初始值为0.进行T次操作,操作有两种:

1>C x1 y1 x2 y2 改变又2点[x1, y1] [x2, y2]确定的矩阵内的值。0变为1, 1变为0

2>Q x y 询问[x,y]点的值为多少

T组输入数据。

每组输入数据第一行2个整数N,M(2 <= N <= 1000, 1 <= M <= 50000)。

接下里的M行代表M次操作:

C x1 y1 x2 y2 (1 <= x1 <= x2 <= N, 1 <= y1 <= y2 <= N) 。

Q x y (1 <= x, y <= N) 。

对于每次的Q操作,输出点(x,y)的值,每个值占一行。

每组数据之后有个换行。

#include<stdio.h>
#include<string.h>
int c[1005][1005],n;
int lowbit(int x)
{
    return x&(-x);
}
int sum(int x,int y)
{
    int i=y, sum=0;
    while(x>0)
    {
        y=i;
        while(y>0)
        {
            sum+=c[x][y];
            y-=Lowbit(y);
        }
        x-=Lowbit(x);
    }
    return sum;
}

void add(int x, int y)
{
    int i=y;
    while(x<=n)
    {
        y=i;
        while(y<=n)
        {
            c[x][y]++;
            y+=Lowbit(y);
        }
        x+=Lowbit(x);
    }
}
int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int T, m, x1, y1, x2, y2, i;
    char ch;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &n, &m);
        memset(c,0,sizeof(c));
        getchar();
        for(i=0; i<m; i++)
        {
            scanf("%c",&ch);
            if(ch=='C')
            {
                scanf("%d %d %d %d", &x1,&y1,&x2,&y2);
                x2++,y2++;
                add(x1,y1,1);
                add(x2,y2,1);
                add(x1,y2,-1);
                add(x2,y1,-1);
            }
            else
            {
                scanf("%d %d", &x1,&y1);
                printf("%d\n", sum(x1, y1)%2);
            }
            getchar();
        }
        puts("");
    }
    return 0;
}






一样,所以小兵不得不每次都一个一个营地的去数,很快就精疲力尽了

小兵很苦恼,这么算他真的会崩溃的,聪明的读者,你能写个程序帮他完成这项工作吗?


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值