zoukankan      html  css  js  c++  java
  • hdu 4267/poj 3468 A Simple Problem with Integers (分状态的树状数组)

    A Simple Problem with Integers

    Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4283    Accepted Submission(s): 1334


    Problem Description
    Let A1, A2, ... , AN be N elements. You need to deal with two kinds of operations. One type of operation is to add a given number to a few numbers in a given interval. The other is to query the value of some element.
     
    Input
    There are a lot of test cases. 
    The first line contains an integer N. (1 <= N <= 50000)
    The second line contains N numbers which are the initial values of A1, A2, ... , AN. (-10,000,000 <= the initial value of Ai <= 10,000,000)
    The third line contains an integer Q. (1 <= Q <= 50000)
    Each of the following Q lines represents an operation.
    "1 a b k c" means adding c to each of Ai which satisfies a <= i <= b and (i - a) % k == 0. (1 <= a <= b <= N, 1 <= k <= 10, -1,000 <= c <= 1,000)
    "2 a" means querying the value of Aa. (1 <= a <= N)
     
    Output
    For each test case, output several lines to answer all query operations.
     
    Sample Input
    4 1 1 1 1 14 2 1 2 2 2 3 2 4 1 2 3 1 2 2 1 2 2 2 3 2 4 1 1 4 2 1 2 1 2 2 2 3 2 4
     
    Sample Output
    1 1 1 1 1 3 3 1 2 3 4 1
     
    Source
     
     树状数组,更新区间,查询单点,区别是加了一个a%k==0的条件限制....
    我们观察到k很小,于是按照k分类....
    每一类再按照余数分类,一共55棵树(1+2+3+...+10)
     
    然后写完交上去,竟然MLE了。。。
    13×13*50007 
    我一开始也想到了是开大了。。。然后改成了11*11*50004,结果还是mle..
    然后我就把代码贴到群里问了。。。。
    然后就被打脸了。。。
    被这顿嘲讽啊。。。
    由于我的vim不知道什么原因,要复制两次才能复制上去。。。
    就是说,改成了11*11*50004的代码并没有提交上去,第二次mle还是13*13*50007。。
    不过也算一个经验:对于低维度(一维)数组,稍微开大点对空间影响不会很大...
    但是高维,稍微开大一点,就会极大的影响空间....因为是乘起来的。
    因为之前很少遇到高维,而且数组比较大的情况,所以没有太注意。
    也说明把数组开大一点就好,一点点。

    代码是按照hdu 4267 写的
    poj 3468和这个差不多,就是读入顺序和op的写法不太一样。
    另:某博客看到的tips,虽然我也知道这个,但我觉得他表达得比较清楚...

    Tips:

    树状数组的优势是方便动态求值和更新..

    可惜树状数组是单点更新

    倒是有个方法可以快速成段更新

    就是在区间【a, b】内更新+x就在a的位置+x 然后在b+1的位置-x

    求某点a的值就是求数组中1~a的和..

    可惜这道题还不是成段更新..而是隔开几个数来更新..

    所以就可以多建几棵树..然后就可以转换为成段更新了~~

    其中每个位置初始值用一个数组保存..在每次询问的时候加上就好..

    /****....*********************************************************************
        > File Name: code/hdu/4267.cpp
        > Author: 111qqz
        > Email: rkz2013@126.com 
        > Created Time: 2015年08月07日 星期五 14时27分58秒
     ************************************************************************/
    
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #include<string>
    #include<map>
    #include<set>
    #include<queue>
    #include<vector>
    #include<stack>
    #define y0 abc111qqz
    #define y1 hust111qqz
    #define yn hez111qqz
    #define j1 cute111qqz
    #define tm crazy111qqz
    #define lr dying111qqz
    using namespace std;
    #define REP(i, n) for (int i=0;i<int(n);++i)  
    typedef long long LL;
    typedef unsigned long long ULL;
    const int inf = 0x7fffffff;
    const int N=5E4+3;
    int c[N][11][11];
    int a[N];
    int n,m,k,del,x,q,y;
    bool flag;
    int lowbit( int x)
    {
        return x&(-x);
    }
    void update ( int a,int b,int x, int delta)
    {
        for ( int i = x; i <= n ; i = i + lowbit (i))
        {
        c[i][a][b] += delta;
        }
    }
    int sum ( int a,int b,int x)
    {
        int res =  0;
        for ( int i  = x;  i >= 1; i = i - lowbit (i))
        {
        res = res + c[i][a][b];
        }
        return res;
    }
    int main()
    {
        while (scanf("%d",&n)!=EOF)
        {
        memset(c,0,sizeof(c));
        flag = true;
    
        for ( int i = 1 ;i <= n ; i++ )
        {
            scanf("%d",&a[i]);
        }
        scanf("%d",&q);
        flag = false;
        int op;
        for ( int i = 1 ; i <= q ; i ++)
        {
            scanf("%d",&op);
            if (op==1)
            {
            scanf("%d %d %d %d",&x,&y,&k,&del);
            update (k,x%k,x,del);
            update(k,x%k,y+1,-del);
            }
            else
            {
            scanf("%d",&x);
            int ans  = a[x];
            for ( int i = 1 ; i <= 10 ; i++)
            {
                ans = ans +sum(i,x%i,x);
            }
            cout<<ans<<endl;
            }
        }
        }
        return 0;
    }
  • 相关阅读:
    find命令
    shell编程基础
    grep命令
    awk命令
    结对项目之需求分析与原型模型设计
    使用Git进行代码管理的心得
    软件工程的实践项目的自我目标
    第五次作业——团队项目——需求规格说明书
    调研android开发环境的发展演变
    结对编程总结
  • 原文地址:https://www.cnblogs.com/111qqz/p/4711191.html
Copyright © 2011-2022 走看看