看了大牛的博客才知道怎么做,头回写这么多棵树,好惊悚
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; }