zoukankan      html  css  js  c++  java
  • 士兵杀死(两)(南阳116)

    士兵杀敌(二)

    时间限制:1000 ms  |  内存限制:65535 KB
    难度:5
    描写叙述

    南将军手下有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号士兵的总杀敌数,每组输出占一行
    例子输入
    5 6
    1 2 3 4 5
    QUERY 1 3
    ADD 1 2
    QUERY 1 3
    ADD 2 3
    QUERY 1 2
    QUERY 1 5
    例子输出
    6
    8
    8
    20

    士兵杀敌(一) 数组是固定的,所以能够用一个sum数组来保存每一个元素的和即可,可是不能每次都加,由于那样会超时。查询次数太多。可是这个士兵杀敌(二)就不能用那个方法来解了,由于这个是动态的,中间元素的值可能会变化。所以引出一个新的东西来。刚開始想了一下,实在是没有想到方法,就去讨论区看了看,一看好像都说用树状数组,就去找树状数组的使用方法。

    先上图。看着图解释easy理解点。

    数组A是原数组中的元素。数组C是树状数组中的元素,图中C数组的元素组成为A中的某些元素之和,这些元素的个数取决于它的下标能被多少个2整除,像C[1] = A[1]; C[2] = A[1] + A[2]; C[3] = A[3]; C[4] = A[1] + A[2] + A[3] + [4] = C[2] + C[3]; ……这些个数能够写一个通式C[i] = A[n - 2^k + 1] + ……+A[i]; 当中k为 i 的二进制中从右往左数的 0 的个数 ,就像6有一个, 6能够写成 2 × 3, 所以C[6] = A[5] + A[6]; 所以能够定义一个函数来求这个数.

    6的二进制为0110

    5的二进制为0101

    6^5 = 0011

    6&(6^5) = 0010 = 十进制中的2

    所以函数能够这么写

    int lowbit(int N)//求n中有多少个能被2的多少次幂整除的。即2^k, 也就是树状数组的作用域
    {
        return N & (N ^ (N - 1));
    }

    也能够写成

    int lowbit(int N)//求n中有多少个能被2的多少次幂整除的,即2^k, 也就是树状数组的作用域
    {
        return N & (-N);
    }

    更改一个数的值, 就要更改次数在树状数组中的全部祖先,只是这个时间复杂度是O(logn); 以下是更改值(加入杀敌数)的函数

    复制代码
    void add(int pos, int num)//加入新值到树状数组中
    {
        while(pos <= n)
        {
            tmp[pos] += num;
            pos += lowbit(pos);
        }
    }
    复制代码

    以下就是求和函数。 由于这样的方法之所以快。是求他的最小树根节点的和, 最小树的个数为当前要求的n的二进制中为1的个数。即展开式中能写成不同2的幂指数的项数。

    比如: 15 = 2^3 + 2^2 + 2^1 + 2^0; 所以n = 15时, 最小数有四个。求和的时间复杂度为O(logn); 

    复制代码
    int Sum(int N)//求前N个数的和
    {
        int sum = 0;
        while(N > 0)
        {
            sum += tmp[N];
            N -= lowbit(N);
        }
        return sum;
    }
    复制代码

    关键就是这三步, 这三步搞明确了,基本上就不成问题了。可是。当时依照 杀敌(一) 中的思维。还统计了一个总数,那样不会快,反而会慢,所以直接求即可。以下是完整的代码


    
    
    #include<stdio.h>
    #include<string.h>
    int a[1000010];
    int n,m;
    int lowbit(int N)//求n中有多少个能被2的多少次幂整除的。即2^k, 也就是树状数组的作用域
    {
        return N&(-N);
    }
    void asd(int i,int M)//加入新值到树状数组中
    {
        while(i<=n)
        {
            a[i]+=M;
            i+=lowbit(i);
        }
    }
    int sum(int N)//求前N个数的和
    {
        int sum=0;
        while(N>0)
        {
            sum+=a[N];
            N-=lowbit(N);
        }
        return sum;
    }
    int main()
    {
        int i,t,a,b;
        char str[10];
        scanf("%d %d",&n,&m);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&t);
            asd(i,t);
        }
        while(m--)
        {
            scanf("%s %d %d",str,&a,&b);
            if(!strcmp(str,"QUERY"))
            printf("%d
    ",sum(b)-sum(a-1));
            else
            asd(a,b);
        }
        return 0;
    }
        
        


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    [恢]hdu 1517
    [恢]hdu 1847
    [恢]hdu 2189
    XHTML学习资料(二)
    基于ASP.NET的lucene.net全文搜索(一)
    XHTML学习资料(三)—— 表格
    ASP.NET中的Menu控件的应用
    基于ASP.NET的lucene.net全文搜索(二)
    EasyFas开源t框架说明
    动态解析XML生成EXCEL
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4828172.html
Copyright © 2011-2022 走看看