题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4267
题意:题目中有两种操作
1.每隔k点更新;
2.查询最底层的叶子节点的值;
思路:因为k不是固定的,但是k的范围又很小,只有1-10,所以我们不妨在每个区域都开一个数组来标记不同的k,代表从最左端的那个点开始,在此区域内,每隔k个点都是有效点。要注意的是,每个区域的起始位置的那个点一定要是有效点。
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define Mid(x,y) (x+y)>>1
const int maxn=50010;
int n;
int arr[maxn];
struct node
{
int left, right, val[11];
}p[4*maxn];
void Build(int l, int r, int rt)
{
memset(p[rt].val, 0, sizeof(p[rt].val));
p[rt].left=l;
p[rt].right=r;
if(r==l) return;
int mid=Mid(l,r);
Build(l, mid, L(rt));
Build(mid+1, r, R(rt));
}
void Update(int l, int r, int k, int c,int rt)
{
if(l>r) return;
if(l==p[rt].left && r==p[rt].right)
{
p[rt].val[k]+=c;
return;
}
int mid=Mid(p[rt].left, p[rt].right);
if(r<=mid) Update(l,r,k,c,L(rt));
else if(l>mid) Update(l,r,k,c,R(rt));
else
{
Update(l,mid,k,c,L(rt));
Update(k+l+((mid-l)/k)*k,r,k,c,R(rt));
}
}
int find(int u)
{
int rt=1;
while(1)
{
if(p[rt].left==p[rt].right) return rt;
int mid=Mid(p[rt].left, p[rt].right);
if(u<=mid) rt=L(rt);
else rt=R(rt);
}
}
int Query(int u, int rt, int num)
{
for(int i=1; i<11; i++)
{
if((u-p[rt].left)%i==0)
{
num+= p[rt].val[i];
}
}
if(rt==1) return num;
return Query(u, rt/2, num);
}
int main()
{
while(~scanf("%d", &n))
{
for(int i=1; i<=n; i++)
{
scanf("%d", &arr[i]);
}
Build(1,n,1);
int m=0,tmp=0;
int a,b,k,c;
scanf("%d", &m);
while(m--)
{
scanf("%d", &tmp);
if(tmp==1)
{
scanf("%d%d%d%d", &a, &b, &k, &c);
Update(a,b,k,c,1);
}
if(tmp==2)
{
scanf("%d", &a);
printf("%d\n", Query(a,find(a),arr[a]));
}
}
}
return 0;
}