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;
}


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