题意:给出n个数两种操作, 1,查询第i个数是什么,2,输入a, b, k, c,然后所有满足在区间[a, b]里面的下标i 满足(i - a)% k == 0的全部加上c。
首先可以将每隔k的数看成一堆(如 x , x + k...),对于每堆都可以由线段树维护。那么,需要开多少颗线段树呢,可以这么看,k最大为10,那么 %k = (0, 1, 2, ....k-1 = 9)共有十堆,也可以当k = 1时,%k = 0(第一个),k = 2时,%k = 0, 1(第二,三个)一直到k = 10,%k = (0, 1, 2, 3...9),加起来一共55堆,这里采用的是后者。至于查询,只需要在k = 1~10时分别求和即可。那么怎么确定对那堆数进行维护呢?我们可以对每堆进行编号,从0 一直到54(因为是模嘛),只要确定是那一堆,就可以解决问题了
由 (i - a )% k== 0,转化为i % k == a % k,有a, k已知,则令j = a % k也已知,由于这里k ~ (1 ~ 10),所以开一个辅助数组t[11] [11],t [ i ] [ j ]表示i % k == a % k == j,即满足(i - a) % k == 0,那么就可以直接对编好号的线段树进行操作就可以了。
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define pi acos(-1.0)
#define eps 1e-8
#define asd puts("sdasdasdasdasd");
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 50050;
struct node{
int l, r, add[55], lazy, x;
}tr[N << 2];
int t[11][11]; // t[i][j]表示 i % k == a % k == j,即满足(i - a) % k == 0
//k = 1时第一个元素为0, k = 2时, 第2,3个元素为0, 1....依次类推
int n, q;
void build( int l, int r, int rt )
{
tr[rt].l = l;
tr[rt].r = r;
memset( tr[rt].add, 0, sizeof( tr[rt].add ) );
tr[rt].lazy = 0;
if( l == r )
{
scanf("%d", &tr[rt].x);
return;
}
int mid = (l + r) >> 1;
build( lson );
build( rson );
}
void down( int rt )
{
if( tr[rt].lazy )
{
tr[rt<<1].lazy += tr[rt].lazy;
tr[rt<<1|1].lazy += tr[rt].lazy;
tr[rt].lazy = 0;
for( int i = 0; i < 55; i++ )
{
tr[rt<<1].add[i] += tr[rt].add[i];
tr[rt<<1|1].add[i] += tr[rt].add[i];
tr[rt].add[i] = 0;
}
}
}
void update( int l, int r, int rt, int k, int mod, int x )
{
if( l <= tr[rt].l && tr[rt].r <= r )
{
tr[rt].lazy += x;
tr[rt].add[ t[k][mod] ] += x;
return;
}
down( rt );
int mid = ( tr[rt].l + tr[rt].r ) >> 1;
if( l <= mid )
update( l, r, rt << 1, k, mod, x );
if( r > mid )
update( l, r, rt << 1 | 1, k, mod, x );
}
int query( int pos, int rt )
{
if( tr[rt].l == tr[rt].r )
{
int res = tr[rt].x;
for( int i = 1; i <= 10; i++ )
res += tr[rt].add[ t[i][pos%i] ];
return res;
}
down( rt );
int mid = ( tr[rt].l + tr[rt].r ) >> 1;
if( pos <= mid )
return query( pos, rt << 1 );
else
return query( pos, rt << 1 | 1 );
}
int main()
{
int cnt = 0;
for( int i = 1; i <= 10; ++i )
{
for( int j = 0; j < i; ++j )
t[i][j] = cnt++;
}
while( ~scanf("%d", &n) )
{
build( 1, n, 1 );
scanf("%d", &q);
int a, b, c, k, op;
while( q-- )
{
scanf("%d", &op);
if( op == 1 )
{
scanf("%d%d%d%d", &a, &b, &k, &c);
update( a, b, 1, k, a % k, c );
}
else
{
scanf("%d", &a);
int ans = query( a, 1 );
printf("%d\n", ans);
}
}
}
return 0;
}