題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4267
題意很簡單,插線問點。
解析:首先要完成一個轉化,轉化以後跟 hdu 4288 非常相似。更新 的時候,(i-a)%k == 0,相當於 i%k == a%k(根據中國同餘定理可證),這樣每次更新的元素就是下標模k等a%k的元素了。k<=10,所以模各個k的所有情況有55種,可以維護55顆線段樹,s[ i ][ j ]表示下標模i等j的元素都加上s[ i ][ j ];查詢點a的時候考慮模k(1<=k<=10)的情況,加上s[ k ][ a%k ]的值。
這道題目內存卡的比較緊,s[ ][ ]數組須得轉化成一維的纔行,即代碼中的sum[ ],s[ i ][ j ]映射到sum[ (i-1)*i/2 + j ],因爲第i顆樹以前有(i-1)*i/2個元素,自己可以思考一下這個地方的巧妙。想了好久才理解。。。
參考代碼:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define lson (root<<1)
#define rson (root<<1|1)
const int N = 50005;
int tree[N*3][55];
int num[N];
void build(int root,int l,int r,int x)
{
if(l == r)
{
tree[root][0] = num[x];
return ;
}
int mid = (l+r)/2;
if(x <= mid) build(lson,l,mid,x);
else build(rson,mid+1,r,x);
}
void update(int root,int l,int r,int a,int b,int k,int c,int m)
{
if(l == a && r == b)
{
int x = m + (k-1)*k/2;
tree[root][x] += c;
return ;
}
int mid = (l+r)>>1;
if(b <= mid) update(lson,l,mid,a,b,k,c,m);
else if(a > mid) update(rson,mid+1,r,a,b,k,c,m);
else
{
update(lson,l,mid,a,mid,k,c,m);
update(rson,mid+1,r,mid+1,b,k,c,m);
}
}
int query(int root,int l,int r,int a)
{
int mid = (l+r)>>1;
int sum = 0;
for(int i = 1,j;i <= 10;i++)
{
j = a%i + (i-1)*i/2;
sum += tree[root][j];
}
if(l == r) return sum;
if(a <= mid) return sum+query(lson,l,mid,a);
else return sum+query(rson,mid+1,r,a);
}
int main()
{
int n,m;
while(scanf("%d",&n) != EOF)
{
memset(tree,0,sizeof(tree));
for(int i = 1;i <= n;++i)
{
scanf("%d",&num[i]);
build(1,1,n,i);
}
scanf("%d",&m);
int s,a,b,k,c;
while(m--)
{
scanf("%d%d",&s,&a);
if(s == 2) printf("%d\n",query(1,1,n,a));
else
{
scanf("%d%d%d",&b,&k,&c);
update(1,1,n,a,b,k,c,a%k);
}
}
}
return 0;
}