看了大牛的博客才知道怎么做,头回写这么多棵树,好惊悚
http://blog.csdn.net/ophunter_lcm/article/details/9455723
意思大概是这样,对于 i=a+n*k,根据同余定理可知 i%k = a%k,k最大为10,那么就可以分为 1+2+3+...+10=55种情况,分别是每种k取模后的不同值,建立这55种线段树,
每次维护值的时候找到对应的线段树进行区间维护即可。
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstdlib>
#include<cmath>
#include<vector>
//#pragma comment(linker, "/STACK:1024000000,1024000000");
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 200000
int kid[]= {0,0,1,3,6,10,15,21,28,36,45};
struct tree
{
int sum[maxn];
void init(int l,int r,int k)
{
sum[k]=0;
if(l==r) return ;
int mid=(l+r)>>1;
init(l,mid,2*k);
init(mid+1,r,2*k+1);
}
void update(int d,int l,int r,int s,int e,int k)
{
if(s==l&&e==r)
{
sum[k]+=d;
return ;
}
if(sum[k])
{
sum[k<<1]+=sum[k];
sum[k<<1|1]+=sum[k];
sum[k]=0;
}
int mid=(s+e)>>1;
if(r<=mid) update(d,l,r,s,mid,k<<1);
else if(l>mid) update(d,l,r,mid+1,e,k<<1|1);
else
{
update(d,l,mid,s,mid,k<<1);
update(d,mid+1,r,mid+1,e,k<<1|1);
}
}
int query(int p,int s,int e,int k)
{
if(s==p&&e==p)
{
return sum[k];
}
if(sum[k])
{
sum[k<<1]+=sum[k];
sum[k<<1|1]+=sum[k];
sum[k]=0;
}
int mid=(s+e)>>1;
if(p<=mid) query(p,s,mid,k<<1);
else query(p,mid+1,e,k<<1|1);
}
} T[55];
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0; i<55; i++)
{
T[i].init(1,n,1);
}
for(int i=1; i<=n; i++)
{
int a;
scanf("%d",&a);
T[0].update(a,i,i,1,n,1);
}
int m;
scanf("%d",&m);
while(m--)
{
int p;
scanf("%d",&p);
if(p==1)
{
int a,b,k,c;
scanf("%d%d%d%d",&a,&b,&k,&c);
int id=kid[k]+a%k;
T[id].update(c,a,b,1,n,1);
}
else
{
int a;
scanf("%d",&a);
int ans=0;
for(int i=1; i<=10; i++)
{
int id=kid[i]+a%i;
ans+=T[id].query(a,1,n,1);
}
printf("%d\n",ans);
}
}
}
return 0;
}