hdu4267--A Simple Problem with Integers(树状数组)

题目链接:点击打开链接

题目大意:有一个n个数的序列,有两种操作1 a b k c 在区间[a,b]内的i,如果满足(i-a)%k == 0 那么第i个数就加上c,

2 a问第a个数的值是什么,首先给出n个数的初始值,然后是q次操作,完成每次操作,如果是询问的话,输出那个值。

第一次考虑用线段树,如果一次操作1 a b k c中[a,b]能覆盖当前线段树的一个小段[l,r]的话,那么对于这个小段中的i,

如果满足(i-a)%k == 0 ,那么第i个数的值就会加c,我们将式子变形一下( (i-l)+(l-a) )%k == 0,这个对于一个给定的i来说,(i-l)的值是确定的,那么只需要枚举k(1~10)就可以计算出会有多少个操作对第i个数存在影响,而且对于不同操作来说如果k和(l-a)%k的值都是相同的,那么他们作用的i也就是相同的,就可以合并。cl[ rt ][ k ][ (l-a)%k ],线段树这样建立,对于每次询问就可以log(n)的时间查询对第i个数的修改情况,在加上初始值,就是最终的结果。

但是这样做一直MLE,所以将它转化成树状数组,把一次修改拆成两部分:

1 a b k c拆成 1 a n k c和1 (b-a)/k*k+a+k n k -c,其中(r-l)/k*k+l+k是从a开始不断累加k中第一个超过b的数,这样就可以保证原来的操作是不变的。

转化成装数组之后,就把原本的每段的l转化成了累加的时候的节点的位置,按照同样的方法储存数据,求每个数在它之前存在的所有操作对它的影响,这样计算出最终结果。

#include <cstdio>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <cmath>
#include <map>
#include <stack>
#include <algorithm>
using namespace std ;
#pragma comment(linker, "/STACK:102400000,102400000")
#define LL __int64
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define root 1,n,1
#define lson l,(l+r)/2,rt<<1
#define rson (l+r)/2+1,r,rt<<1|1
#define int_rt int l,int r,int rt
const int mod=1e9+7;
const int MAXN = 50000+10 ;
int cl[MAXN][11][11] , a[MAXN] ;
int n , q ;
int lowbit(int x) {
    return x & -x ;
}
void add(int a,int k,int c) {
    int i = a , temp ;
    while( i <= n ) {
        temp = (i-a)%k ;
        if( temp == 0 ) temp = k ;
        cl[i][k][temp] += c ;
        i += lowbit(i) ;
    }
}
int sum(int a) {
    int i = a , j , temp , ans = 0 ;
    while( i ) {
        for(j = 1 ; j < 11 ; j++)
            ans += cl[i][j][ j-(a-i)%j ] ;
        i -= lowbit(i) ;
    }
    return ans ;
}
int main() {
    int i , j , k , l , r , c ;
    while( scanf("%d", &n) != EOF ) {
        for(i = 1 ; i <= n ; i++)
            scanf("%d", &a[i]) ;
        memset(cl,0,sizeof(cl)) ;
        scanf("%d", &q) ;
        while( q-- ) {
            scanf("%d", &i) ;
            if( i == 1 ) {
                scanf("%d %d %d %d", &l, &r, &k, &c) ;
                add(l,k,c) ;

                add((r-l)/k*k+l+k,k,-c) ;
            }
            else {
                scanf("%d", &i) ;
                printf("%d\n", sum(i)+a[i]) ;
            }
        }
    }
    return 0 ;
}

版权声明:转载请注明出处:http://blog.csdn.net/winddreams

时间: 2024-08-28 12:27:47

hdu4267--A Simple Problem with Integers(树状数组)的相关文章

HDU 4267 A Simple Problem with Integers (树状数组)

A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) 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

poj 3468 A Simple Problem with Integers 树状数组 或 线段树

题目链接:http://poj.org/problem?id=3468 一般说来 树状数组是 [单点更新 区间查询] 而本题是“区间更新 区间查询” 所以要改成维护前缀和 推公式的过程见<挑战程序设计竞赛>第181~182面 代码中bit0是i的零次项 bit1是i的一次项 以后以此类推 在[l, r]加数的时候 写出公式 在l的地方 一次项及以上的直接写 然后在零次项那减去 在r的地方 一次项及以上的减掉之前加上的 然后再零次项那加上“公式化简之后的最终结果 减去 之前在零次项加的那一项”

POJ3468 A Simple Problem with Interger [树状数组,差分]

题目传送门 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 130735   Accepted: 40585 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One

A Simple Problem with Integers_树状数组

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 a

HDU4267 A Simple Problem with Integers 线段树/树状数组

HDU4267 A Simple Problem with Integers  线段树/树状数组 2012长春网络赛A题 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. T

HDU4267 A Simple Problem with Integers

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4267 题意:题目中有两种操作 1.每隔k点更新: 2.查询最底层的叶子节点的值: 思路:因为k不是固定的,但是k的范围又很小,只有1-10,所以我们不妨在每个区域都开一个数组来标记不同的k,代表从最左端的那个点开始,在此区域内,每隔k个点都是有效点.要注意的是,每个区域的起始位置的那个点一定要是有效点. 代码如下: #include<cstdio> #include<cstring>

POJ 3468 A Simple Problem with Integers(树状数组区间更新)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 97217   Accepted: 30358 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of

A Simple Problem with Integers 多树状数组分割,区间修改,单点求职。 hdu 4267

A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4032    Accepted Submission(s): 1255 Problem Description Let A1, A2, ... , AN be N elements. You need to deal with

POJ 3468 A Simple Problem with Integers 【树状数组】

题目链接:http://poj.org/problem?id=3468 题目大意:给出一组数组v[i],有两种操作,一种给出两个数a,b,要求输出v[a]到v[b]之间的和,另一种给出三个数a,b,c,让v[a]到v[b]之间的数全都加上c. 完全是树状数组能够实现的功能,但是如果就这样单纯的套用模板,做第二种操作是更新每个值,这样的操作就有可能超时. 换一种思路,既然第二种操作是给某区间上的所有数加上相同的值,那么应该是能够简化的才对. 假设数组sum[i]为原数组从v[1]到v[i]的和,数

HDU 4267 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): 4000    Accepted Submission(s): 1243 Problem Description Let A1, A2, ... , AN be N elements. You need to deal with