题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=4267
树状数组。
2012长春网赛。。。
46分左右1Y。。
一开始被小胖误导去敲线段树,后来发现用线段树敲,空间需求太大,并且操作麻烦。。。
重新写了个树状数组,花了十多分钟。 区间更新、单点查询。。。
其实只要能想到方法,敲起来很容易~。。。
首先要说一下, ( u - i ) % k == 0,可以转化一下,变成 i % k == u % k == mod 。
于是就可以用下面的方法来做~~
我们用tree[v][k][mod]来表示树状数组的状态。
假如a、b、c、k,那么用树状数组,区间更新,update(b,a%k,k,c),update(a-1,a%k,k,-c) ,就可以了~~~
也就是说,区间[1,b]内每个ui % k == mod ,那么ui 的值就加c ,然后[1,a-1]区间内每一个ui-c,于是就完成了[a,b]这个区间内的更新了~~
查询q的时候也容易,枚举k的每一种状态i(1~10),然后得到 mod = q%i 时的情况~~~ 单个查询的时间复杂度O(10logn) ...
#include<cstdio>
int n,s[50010];
int tree[50010][11][10];
int lowbit(int v){
return v&-v;
}
void INIT(){
int i,j,k;
for(i=1;i<=n;i++)
for(j=1;j<=10;j++)
for(k=0;k<=9;k++)
tree[i][j][k]=0;
}
void update(int mod,int k,int v,int add){
while(v>0){
tree[v][k][mod]+=add;
v-=lowbit(v);
}
}
int query(int a,int v){
int sum=0,i;
while(v<=n){
for(i=1;i<=10;i++){
sum+=tree[v][i][a%i];
}
v+=lowbit(v);
}
return sum;
}
int main(){
int op,i,a,b,k,q,add;
while(~scanf("%d",&n)){
INIT();
for(i=1;i<=n;i++){
scanf("%d",&s[i]);
}
scanf("%d\n",&q);
while(q--){
scanf("%d",&op);
if(op==1){
scanf("%d%d%d%d",&a,&b,&k,&add);
update(a%k,k,b,add);
update(a%k,k,a-1,-add);
}
else{
scanf("%d",&a);
printf("%d\n",query(a,a)+s[a]);
}
}
}
return 0;
}