题意:
n个数字
下面n个数字表示数列
2个操作
1 [u, v] k add
[u,v ]区间 (u点要计算)每隔k个位置,该数字+add
2 pos
询问 pos下标的值(下标从1开始)
思路:
因为k很小, 可以直接存 k[11]
注意查询时, 先找到 pos 所在的 叶子节点
再向上 添加 对应k位置的值
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
#include<queue>
#include<string.h>
#include<map>
#include<set>
#include<stack>
#include<vector>
#include<math.h>
#define inf 10000000
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define Mid(x,y) ((x+y)>>1)
#define ll __int64
using namespace std;
inline ll Min(ll a,ll b){return a>b?b:a;}
inline ll Max(ll a,ll b){return a<b?b:a;}#define N 51000
struct node{ll l, r;ll k[11];
}tree[N*16];
ll a[N];void build(ll l, ll r, ll id){memset(tree[id].k, 0, sizeof(tree[id].k));tree[id].l = l, tree[id].r = r;if(l == r) return ;ll mid = Mid(l, r);build(l, mid, L(id));build(mid+1, r, R(id));
}void updata(ll l, ll r, ll pos, ll add, ll id){if(l > r)return ;if(l == tree[id].l && tree[id].r == r){tree[id].k[pos] += add;return;}ll mid = Mid(tree[id].l, tree[id].r);if(r<=mid)updata(l, r, pos, add, L(id));else if(mid<l)updata(l, r, pos, add, R(id));else{updata(l, mid, pos, add, L(id));updata(l + ((mid-l)/pos+1)*pos,r,pos, add, R(id));}
}ll find(ll pos){ll id = 1;while(1){if(tree[id].l == tree[id].r) return id;ll mid = Mid(tree[id].l, tree[id].r);if(pos <= mid) id = L(id);else id = R(id);}
}ll query(ll pos, ll id, ll num){for(ll i =1;i<11 ;i++)if((pos-tree[id].l) % i==0)num += tree[id].k[i];if(id == 1) return num;return query(pos, id/2, num);
}int main(){ll i, j, n, que;ll u, v, mod, add;while(~scanf("%I64d",&n)){for(i=1;i<=n;i++)scanf("%I64d",&a[i]);build(1, n, 1);scanf("%I64d",&que);while(que--){scanf("%I64d",&i);if(i==2){scanf("%I64d",&j);printf("%I64d\n",query(j ,find(j), a[j]));}else{scanf("%I64d %I64d %I64d %I64d",&u,&v,&mod,&add);updata(u, v, mod, add, 1);}}}return 0;
}
/*
10
0 0 0 0 0 0 0 0 0 0
99
1 1 10 2 5
2 1
2 2
2 3
2 4
2 5
2 9
2 10
1 3 6 3 10
2 3
2 4
2 5
2 6ans:
5
0
5
0
5
5
0
15
0
5
10*/