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

    1. 什么是树状数组?

       假设C [i]表示这个数据结构的第i个元素,  A [i]表示第i数的数值。

          C [i] = A [i] ( i 为奇数)

        C [i] = A [k] + .. + A [i];  (k 等于 i的二进制最后一位1去掉 + 1,  i为偶数)

       看图, 

    2.  想法

        感觉这是某个理论的衍生物,或者是多个理论的杂交物。

    3.  应用

      经常用在对紧挨着的大量的数字进行相加, 而且其中会修改某一位数字, 其时间复杂度 logn.

    4.  我用它解决这个问题(附上代码)

    描述

    南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的。

    小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。

    南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数。

    输入
    只有一组测试数据
    第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示指令的条数。(1<M<100000)
    随后的一行是N个整数,ai表示第i号士兵杀敌数目。(0<=ai<=100)
    随后的M行每行是一条指令,这条指令包含了一个字符串和两个整数,首先是一个字符串,如果是字符串QUERY则表示南将军进行了查询操作,后面的两个整数 m,n,表示查询的起始与终止士兵编号;如果是字符串ADD则后面跟的两个整数I,A(1<=I<=N,1<=A<=100), 表示第I个士兵新增杀敌数为A.
    输出
    对于每次查询,输出一个整数R表示第m号士兵到第n号士兵的总杀敌数,每组输出占一行
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #define MAX_SIZE 1000000
    #define CMD_MAX_SIZE 10
    
    int c [MAX_SIZE + 1] = {0}; //树状数组
    int a [MAX_SIZE + 1] = {0};
    
    int
    main(void)
    {
            int N,M;
            int temp;
            int sum = 0;
            int i, j;
            char cmdStr [CMD_MAX_SIZE];
            int m, n;
    
            int GetLast(int value);
            int GetSum(int n);
            void AddIt(int index, int value, int maxSize);
    
            memset((unsigned char *)c, 0, (MAX_SIZE + 1) * sizeof(int)); //清零
            memset((unsigned char *)a, 0, (MAX_SIZE + 1) * sizeof(int));
    
            scanf("%d%d",&N,&M);
            for(i = 1; i <= N; i ++) //初始化
            {
                    scanf("%d", &a [i]);
                    if(i % 2 == 0)
                    {
                            for(j = i - GetLast(i) + 1; j <= i; j ++)
                            {
                                c [i] += a [j];
                            }
                    }
                    else
                    {
                            c [i] = a [i];
                    }
            }
    
            while(M --)
            {
                    fscanf(stdin, "%s %d %d", cmdStr, &m, &n); //或者i和addNum
                    if(!strcmp(cmdStr, "QUERY"))
                    {
                            fprintf(stdout, "%d
    ", GetSum(n) - GetSum(m - 1) );
     }
                    else if(!strcmp(cmdStr, "ADD"))
                    {
                            AddIt(m, n, N);
                    }
                    else
                    {
                            exit(EXIT_FAILURE);
                    }
            }
            return 1;
    }
    
    /*
     * 获取整数的二进制形式左数最后一个1
     * value -- 指定整数
     * 返回结果。
     */
    int
    GetLast(int value)
    {
            return value & (-value);
    }
    /*
     * 获取前n个数的和
     * n -- 表示前n个数
     * 返回它们的和。
     */
    int
    GetSum(int n)
    {
            int sum = 0;
    
            while(n > 0)
            {
                    sum += c [n];
                    n -= GetLast(n);
            }
            return sum;
    }
    
    /*
     * 给某个元素加值
     * index -- 指定元素的序号
     * value -- 加的数值
     * maxSize -- 树状数组的上界
     */
    void
    AddIt(int index, int value, int maxSize)
    {
            int GetLast(int value);
    
            while(index <= maxSize)
            {
                    c [index] += value;
                    index += GetLast(index);
            }
    }
    View Code
  • 相关阅读:
    unity_动画_状态机
    有内涵的技术论坛
    ios开发——常用经典算法OC篇&冒泡/快速
    iOS开发——C篇&文件操作
    iOS开发——C篇&预处理
    iOS开发——C篇&结构体与枚举
    iOS开发——C篇&函数解析
    iOS开发——C篇&动态内存分析
    UML第二次作业(代码互评)
    我与UML相爱相杀的狗血日常
  • 原文地址:https://www.cnblogs.com/the-one/p/6544212.html
Copyright © 2011-2022 走看看