题目:点击打开链接
长春赛区网络赛的题,也是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;
}