/*
显然这道题应该用线段树来做,区间更新、多次查找,然而线段树中状态比较多,需要用多个线段树来表示这些状态。
原来线段树中c[][]为一个二维数组,c[k][u],其中k表示余数,u表示a%k,这样共有55种情况,不过最后内存超,然后用一维表示,通过。
思路:(i - a) % k == 0 可以等效于 i % k == a % k
*/
#include <cstdio>
#include <cstring>
const int nMax = 50001;
struct Tree
{
int l, r;
int c[57];//[11][11];
}tree[nMax * 4];
int A[nMax];
int N, Q;
void build(int rt, int l, int r)
{
if(l < r)
{
int mid = (l + r) / 2;
build(rt * 2, l, mid);
build(rt * 2 + 1, mid + 1, r);
}
tree[rt].l = l;
tree[rt].r = r;
memset(tree[rt].c, 0, sizeof(tree[rt].c));
}
void update(int rt, int u, int k, int l, int r, int c)
{
if((tree[rt].l == l) && (tree[rt].r == r))
{
int index = k * (k - 1) / 2 + u;
tree[rt].c[index] += c;
}
else
{
int mid = (tree[rt].l + tree[rt].r) / 2;
if(r <= mid)
update(rt * 2, u, k, l, r, c);
else if(mid + 1 <= l)
update(rt * 2 + 1, u, k, l, r, c);
else
{
update(rt * 2, u, k, l, mid, c);
update(rt * 2 + 1, u, k, mid + 1, r, c);
}
}
}
void search(int rt, int a, int &w)
{
int i;
for(i = 1; i <= 10; ++ i)
{
int index = i * (i - 1) / 2 + a % i;
if(tree[rt].c[index] != 0)
w += tree[rt].c[index];
}
if(tree[rt].l == tree[rt].r) return;
int mid = (tree[rt].l + tree[rt].r) / 2;
if(a <= mid)
search(rt * 2, a, w);
else if(mid + 1 <= a)
search(rt * 2 + 1, a, w);
}
int main()
{
//freopen("e://data.in", "r", stdin);
//freopen("e://data2.out", "w", stdout);
int a, b, k, c;
int i;
while(scanf("%d", &N) != EOF)
{
for(i = 1; i <= N; ++ i) scanf("%d", &A[i]);
build(1, 1, N);
scanf("%d", &Q);
while(Q --)
{
int t;
scanf("%d", &t);
if(t == 1)
{
scanf("%d%d%d%d", &a, &b, &k, &c);
update(1, a % k, k, a, b, c);
}
else
{
scanf("%d", &a);
int w = 0;
search(1, a, w);
printf("%d\n", w + A[a]);
}
}
}
return 0;
}
HDOJ 4267 A Simple Problem with Integers(线段树)
最新推荐文章于 2019-05-13 18:38:38 发布