HDOJ 4267 A Simple Problem with Integers(线段树)

/*
显然这道题应该用线段树来做,区间更新、多次查找,然而线段树中状态比较多,需要用多个线段树来表示这些状态。
原来线段树中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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值