题意:经典的区间更新,单点查询。但是在更新的时候,只更新满足(i - a) % k == 0的点。a为区间左端点。
按同余类建55个树状数组,更新的时候落实到具体某一个树状数组上,查询的时候,按i模1~10所得的值去查询对应的树状数组。当然,用线段树也是一样的。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 50000 + 10;
int c[11][11][maxn];
int num[maxn];
int n, q;
inline int lowbit(int t) { return t & (-t); }
inline void add(int pos, int x, int a, int b) { while(pos > 0) { c[a][b][pos] += x; pos -= lowbit(pos); } }
inline int sum(int pos, int a, int b) { int s = 0; while(pos <= n) { s += c[a][b][pos]; pos += lowbit(pos); } return s; }
void prework()
{
memset(c, 0, sizeof(c));
for(int i = 1; i <= n; ++i)
scanf("%d", num + i);
scanf("%d", &q);
}
void solve()
{
while(q--)
{
int cas; scanf("%d", &cas);
if(cas == 1)
{
int a, b, k, c;
scanf("%d %d %d %d", &a, &b, &k, &c);
int mod = a % k, ln = 0, rn = 0;
ln = (a - 1) / k;
for(int i = ln * k + 1; i < a; ++i) if(i % k == mod) ln++;
rn = b / k;
for(int i = rn * k + 1; i <= b; ++i) if(i % k == mod) rn++;
add(ln, -c, k, mod); add(rn, c, k, mod);
}
else
{
int a; scanf("%d", &a);
long long ans = num[a];
for(int i = 1; i <= 10; ++i)
{
int mod = (a % i) ? 1 : 0;
ans += sum(a / i + mod, i, a % i);
}
printf("%d\n", ans);
}
}
}
int main()
{
freopen("in.txt", "r", stdin);
while(~scanf("%d", &n))
{
prework();
solve();
}
return 0;
}