http://acm.hdu.edu.cn/showproblem.php?pid=4267
/*
参考网上结题报告:
线段树
(i-a)%k = 0 即i%k=a%k
节点维护一个二维数组add, add[a][b]=c,表示该区间下标i%a=b的加c
那么, update(l, r, k, l%k, v)这样就可以分到子区间了
但是, 这样会爆内存,因为a%b<b,可以节省一半, 这样就过了..
*/
#include<iostream>
#include<algorithm>
#include<memory.h>
#include<cstdio>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
const int maxn=50002;
int A[maxn],col[maxn*3][55];
void updata(int rt,int l,int r,int a,int b,int k,int mod,int c)
{
if(a<=l&&r<=b)
{
int st=mod+k*(k-1)/2;
col[rt][st]+=c;
return ;
}
int mid=(l+r)>>1;
if(a<=mid)
updata(lson,a,b,k,mod,c);
if(b>mid)
updata(rson,a,b,k,mod,c);
}
int query(int rt,int l,int r,int idx)
{
int res=0;
for(int i=1;i<=10;i++)
{
int st=idx%i+i*(i-1)/2;
res+=col[rt][st];
}
if(l==r) return res;
int mid=(l+r)>>1;
if(idx<=mid)
res+=query(lson,idx);
if(idx>mid)
res+=query(rson,idx);
return res;
}
int main()
{
int n,q;
while(scanf("%d",&n)!=EOF)
{
int i,k,a,b,c,cmd,indx;
memset(col,0,sizeof(col));
for(i=1; i<=n; i++)
{
scanf("%d",&A[i]);
}
scanf("%d",&q);
while(q--)
{
scanf("%d",&cmd);
if(cmd==2)
{
scanf("%d",&indx);
printf("%d\n",A[indx]+query(1,1,n,indx));
}
else
{
scanf("%d%d%d%d",&a,&b,&k,&c);
updata(1,1,n,a,b,k,a%k,c);
}
}
}
return 0;
}
/*
4
1 1 1 1
14
1 2 3 1 2
2 1
2 2
2 3
2 4
1 1 4 2 1
2 1
2 2
2 3
2 4
*/