Hdu 4267 树状数组成段更新.cpp
题意:
给出 n 表示有 n 个位置
然后有 一行 n 个数表示初始状态 每个位置的值
然后给出 m 表示有 m 条order
接下来 m 行..
每行的格式有两种..
1 b 表示询问在 b 点的值
2 a b k x 表示在 a 到 b 里面满足 (i-a)%k == 0 的位置上的值都加 x
思路:
感觉是树状数组了
但是 树状数组是单点更新 而题目要求是在a b 内每隔 k 个数更新..
如果用for循环对a b 内每隔 k 个位置的数更新就会很费时间..
所以有一个方法就是 按 k 值 i%k 值还有 i/k+1 值把每隔 k 个位置的值都分组..即按 k 值和 i%k 值建树状数组
到时候维护其中一棵 树状数组就好了..
维护的方法是在c[ k ][a%k][(i-a)/k+1] + 1 在c[ k ][a % k ][ (a/k) + (b-a)/k + 2 ] - 1..
关于建成的树状数组..
更新时有55种情况
1,2,3,4,5......
1,3,5,7,9......
2,4,6,8,10....
1,4,7,10,13...
2,5,9,12,15...
3,6,10,13,16...
.
.
.
10,20,30,40,50...
所以用55个树状数组.
Tips:
树状数组的优势是方便动态求值和更新..
可惜树状数组是单点更新
倒是有个方法可以快速成段更新
就是在区间【a, b】内更新+x就在a的位置+x 然后在b+1的位置-x
求某点a的值就是求数组中1~a的和..
可惜这道题还不是成段更新..而是隔开几个数来更新..
所以就可以多建几棵树..然后就可以转换为成段更新了~~
其中每个位置初始值用一个数组保存..在每次询问的时候加上就好..
※ 因为输入数据a, b什么的都是从1 开始的.. 而最后要求 ***********不懂..到时候问zz问清楚了再写上..
Code:
1 #include <stdio.h> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 6 int n; 7 int c[12][12][50010]; 8 int lowbit(int x) 9 { 10 return (x)&(-x); 11 } 12 void modify(int i, int j, int pos,int x) 13 { 14 while(pos<=n) 15 { 16 c[i][j][pos]+=x; 17 pos+=lowbit(pos); 18 } 19 } 20 int getSum(int i, int j, int x) 21 { 22 int sum=0; 23 while(x>0) 24 { 25 sum+=c[i][j][x]; 26 x-=lowbit(x); 27 } 28 return sum; 29 } 30 31 int main() 32 { 33 int i, j; 34 int m, ans; 35 int a, b, k, x, order; 36 int arr[50010]; 37 while(scanf("%d", &n) != EOF) 38 { 39 memset(c,0,sizeof(c)); 40 for(i = 1; i <= n; ++i) 41 scanf("%d", &arr[i]); 42 43 scanf("%d", &m); 44 while(m--) { 45 scanf("%d", &order); 46 if(order == 1) { 47 scanf("%d %d %d %d", &a, &b, &k, &x); 48 // a--, b--; 49 int kk = (b-a)/k; 50 modify(k, a%k, a/k+1, x); 51 modify(k, a%k, a/k+kk+2, -x); 52 } 53 else if(order == 2) { 54 scanf("%d", &b); 55 // b--; 56 ans = arr[b]; 57 for(i = 1; i <= 10; ++i) { 58 ans += getSum(i, b%i, b/i+1); 59 } 60 printf("%d\n", ans); 61 } 62 } 63 } 64 65 return 0; 66 }
题目链接: