题目链接: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; }
时间: 2024-10-03 12:50:43