/* 显然这道题应该用线段树来做,区间更新、多次查找,然而线段树中状态比较多,需要用多个线段树来表示这些状态。 原来线段树中c[][]为一个二维数组,c[k][u],其中k表示余数,u表示a%k,这样共有55种情况,不过最后内存超,然后用一维表示,通过。 思路:(i - a) % k == 0 可以等效于 i % k == a % k */ #include <cstdio> #include <cstring> const int nMax = 50001; struct Tree { int l, r; int c[57];//[11][11]; }tree[nMax * 4]; int A[nMax]; int N, Q; void build(int rt, int l, int r) { if(l < r) { int mid = (l + r) / 2; build(rt * 2, l, mid); build(rt * 2 + 1, mid + 1, r); } tree[rt].l = l; tree[rt].r = r; memset(tree[rt].c, 0, sizeof(tree[rt].c)); } void update(int rt, int u, int k, int l, int r, int c) { if((tree[rt].l == l) && (tree[rt].r == r)) { int index = k * (k - 1) / 2 + u; tree[rt].c[index] += c; } else { int mid = (tree[rt].l + tree[rt].r) / 2; if(r <= mid) update(rt * 2, u, k, l, r, c); else if(mid + 1 <= l) update(rt * 2 + 1, u, k, l, r, c); else { update(rt * 2, u, k, l, mid, c); update(rt * 2 + 1, u, k, mid + 1, r, c); } } } void search(int rt, int a, int &w) { int i; for(i = 1; i <= 10; ++ i) { int index = i * (i - 1) / 2 + a % i; if(tree[rt].c[index] != 0) w += tree[rt].c[index]; } if(tree[rt].l == tree[rt].r) return; int mid = (tree[rt].l + tree[rt].r) / 2; if(a <= mid) search(rt * 2, a, w); else if(mid + 1 <= a) search(rt * 2 + 1, a, w); } int main() { //freopen("e://data.in", "r", stdin); //freopen("e://data2.out", "w", stdout); int a, b, k, c; int i; while(scanf("%d", &N) != EOF) { for(i = 1; i <= N; ++ i) scanf("%d", &A[i]); build(1, 1, N); scanf("%d", &Q); while(Q --) { int t; scanf("%d", &t); if(t == 1) { scanf("%d%d%d%d", &a, &b, &k, &c); update(1, a % k, k, a, b, c); } else { scanf("%d", &a); int w = 0; search(1, a, w); printf("%d\n", w + A[a]); } } } return 0; }