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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4267


题意很简单,插线问点。

解析:首先要完成一个转化,转化以后跟 hdu 4288 非常相似。更新 的时候,(i-a)%k == 0,相当于 i%k == a%k(根据中国同余定理可证),这样每次更新的元素就是下标模k等a%k的元素了。k<=10,所以模各个k的所有情况有55种,可以维护55颗线段树,s[ i ][ j ]表示下标模i等j的元素都加上s[ i ][ j ];查询点a的时候考虑模k(1<=k<=10)的情况,加上s[ k ][ a%k ]的值。

这道题目内存卡的比较紧,s[ ][ ]数组须得转化成一维的才行,即代码中的sum[ ],s[ i ][ j ]映射到sum[ (i-1)*i/2 + j ],因为第i颗树以前有(i-1)*i/2个元素,自己可以思考一下这个地方的巧妙。想了好久才理解。。。

参考代码:

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;

#define lson (root<<1)
#define rson (root<<1|1)

const int N = 50005;

int tree[N*3][55];
int num[N];

void build(int root,int l,int r,int x)
{
	if(l == r)
	{
		tree[root][0] = num[x];
		return ;
	}
	int mid = (l+r)/2;
	if(x <= mid) build(lson,l,mid,x);
	else build(rson,mid+1,r,x);
}

void update(int root,int l,int r,int a,int b,int k,int c,int m)
{
	if(l == a && r == b)
	{
		int x = m + (k-1)*k/2;
		tree[root][x] += c;
		return ;
	}
	int mid = (l+r)>>1;
	if(b <= mid) update(lson,l,mid,a,b,k,c,m);
	else if(a > mid) update(rson,mid+1,r,a,b,k,c,m);
	else 
	{
		update(lson,l,mid,a,mid,k,c,m);
		update(rson,mid+1,r,mid+1,b,k,c,m);
	}
}

int query(int root,int l,int r,int a)
{
	int mid = (l+r)>>1;
	int sum = 0;
	for(int i = 1,j;i <= 10;i++)
	{
		j = a%i + (i-1)*i/2;
		 sum += tree[root][j];
	}
	if(l == r) return sum;
	if(a <= mid) return sum+query(lson,l,mid,a);
	else return sum+query(rson,mid+1,r,a);
}

int main()
{
	int n,m;
	while(scanf("%d",&n) != EOF)
	{
		memset(tree,0,sizeof(tree));
		for(int i = 1;i <= n;++i)
		{
			scanf("%d",&num[i]);
			build(1,1,n,i);
		}
		scanf("%d",&m);
		int s,a,b,k,c;
		while(m--)
		{
			scanf("%d%d",&s,&a);
			if(s == 2) printf("%d\n",query(1,1,n,a));
			else
			{
				scanf("%d%d%d",&b,&k,&c);
				update(1,1,n,a,b,k,c,a%k);
			}
		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章