http://acm.hdu.edu.cn/showproblem.php?pid=4267
一道加强版的树状数组题,利用题目的关键点——除数较小,可以想到将除数跟余数分类,最多分成55种情况,也就是每个结点存放55个数据的的树状数组。
建树相对简单,遵循思路,直接构建【区间修改,单点查询】的树状数组。就是query的时候比较难想懂,不过明白构树的原理,反过来就可以知道query时要查询那些数据了。在query的时候,只需要将查询的点除以除数得到余数,然后对被查询的数、除数以及余数相应的位置进行树状数组的叠加操作,最后输出结果即可。
1y代码:
View Code
1 //hdu 4267 BIT by Lyon 2 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 7 const int maxn = 50005; 8 typedef __int64 ll; 9 10 int node[maxn][11][10]; 11 12 void addSeg(int x, int add, int k, int r){ 13 for (; x > 0; x -= x & (-x)) node[x][k][r] += add; 14 } 15 16 ll query(int x, int end){ 17 ll ret = 0; 18 19 for (int i = 1; i < 11; i++){ 20 int r = x % i; 21 22 for (int t = x; t <= end; t += t & (-t)) ret += node[t][i][r]; 23 } 24 25 return ret; 26 } 27 28 void deal(int n){ 29 for (int i = 1; i <= n; i++){ 30 int a; 31 32 scanf("%d", &a); 33 addSeg(i - 1, -a, 1, 0); 34 addSeg(i, a, 1, 0); 35 } 36 37 int m; 38 39 scanf("%d", &m); 40 while (m--){ 41 int op; 42 43 scanf("%d", &op); 44 switch (op){ 45 case 1:{ 46 int a, b, k, c; 47 48 scanf("%d%d%d%d", &a, &b, &k, &c); 49 50 int t = a % k; 51 52 addSeg(a - 1, -c, k, t); 53 addSeg(b, c, k, t); 54 } break; 55 case 2:{ 56 int x; 57 58 scanf("%d", &x); 59 printf("%I64d\n", query(x, n)); 60 } break; 61 } 62 } 63 } 64 65 int main(){ 66 int n; 67 68 while (~scanf("%d", &n)){ 69 memset(node, 0, sizeof(node)); 70 deal(n); 71 } 72 73 return 0; 74 }
——written by Lyon