题目:点击打开链接
长春赛区网络赛的题,也是2012年五大区网络赛第一场的第一个题,当时智商拙计,连树状数组和线段树的大名也没有听说过,居然以为是模拟被大神们好一阵修理。。
现在学习了树状数组,写起来也是磕磕绊绊,参阅了若干大神的若干资料,终于凑合了这个三维树状数组的更新。和一般的树状数组不同的是,为节约时间,尽量不TLE,我们的第二维是K,第三维是a%k(为什么是这个呢?原式中的(i-a)%k==0可以移向的。。更新的时候也是按照这个余数来跳着更新,忽忽悠悠就这么过了。。。。
//(i-a)%k==0可以换成i%k==a%k,这个思路转自大神blog #include <iostream> #include <stdio.h> #include <string.h> using namespace std; int numpack[60000],N; int c[60000][11][11]; //第二维为k,第三维为mod int lowbit(int x) { return x&(-x); } void update_addnum(int pos,int delta,int mod,int k) //修改成三维的 { for(int i=pos;i>0;i-=lowbit(i)) { c[i][k][mod]+=delta; } } void update_subnum(int pos,int delta,int mod,int k) //修改成三维的 { for(int i=pos;i>0;i-=lowbit(i)) { c[i][k][mod]-=delta; } } int find_add(int x) { int a=x; int result=0; for(int i=x;i<=N;i+=lowbit(i)) { for(int j=1;j<=10;j++) { result+=c[i][j][a%j]; //把第二维遍历一遍 } } return result; } int main() { while(scanf("%d",&N)!=EOF) { memset(numpack,0,sizeof(numpack)); memset(c,0,sizeof(c)); for(int i=1;i<=N;i++) { scanf("%d",&numpack[i]); } int opernum,oper,a,b,c,k; scanf("%d",&opernum); while(opernum--) { scanf("%d",&oper); if(oper==1) { scanf("%d%d%d%d",&a,&b,&k,&c); update_addnum(b,c,a%k,k); update_subnum(a-1,c,a%k,k); } if(oper==2) { int idx; scanf("%d",&idx); int res=numpack[idx]+find_add(idx);//更新值加原始值 printf("%d\n",res); } } } return 0; }