hdu3874Necklace--树状数组

本文介绍了一种利用树状数组实现区间操作优化的算法,通过将询问区间按照R值从小到大排序,并结合哈希表记录每个值首次出现的位置,实现了高效的数据查询与更新。该算法特别适用于需要频繁进行区间查询与更新的场景,如在线编辑系统、实时数据处理等。
//思路:1) 首先将询问的区间[L,R]按照R从小到大排序,这样R前面的都小于等于R
//      2) 利用树状数组求解,m_hash{value] = index;表示值value存放在m_hash数组的index位置
//    并且在m_hash数组中index之前的数只出现过一次
//      3) 当我们现在当前的index比R小,则说明从[Index]到R还有数可以继续放到m_hash数组中
//         a)若m_hash.find(value) != m_hash.end() 则说明,这个value在index之前已经出现过了,所以我们把它从树状数组中删除
//         同时更新树状数组,把以前的value删掉,以前这个value的index = m_hash[value],然后转到c;
//         b)若m_hash(value) == m_hash.end(), 说明value在index之前从来没有出现过,是个新值,我们直接转到c,直接更新树状数组
//         c)update(index, value); m_hash[value] = index;index++;
//      注意:由于数组较大,所以使用__int64位;
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;

#define NSIZ 50010
#define MSIZ 200010
__int64 tree[NSIZ];
__int64 sum[MSIZ];
typedef struct Node_
{
	int x, y;
	int index;
}Node;

Node nodes[MSIZ];
int arr[NSIZ];
map<int, int> m_hash;

int cmp(Node a, Node b)
{
	if (a.y == b.y)
	{
		return a.x < b.x;
	}

	return a.y < b.y;

}

int  lowbit(int n)
{
	return n&(-n);
}

void udpate(int n, int i, int x)
{
	while(i <= n)
	{
		tree[i] += x;
		i += lowbit(i);
	}
}

__int64 getsum(int i)
{
	__int64 sum = 0;
	while(i >= 1)
	{
		sum += tree[i];
		i -= lowbit(i);
	}
	
	return sum;
}

int main()
{
	int t, i;
	int n, a;
	int m;

	scanf("%d", &t);
	int num;

	while(t--)
	{
		scanf("%d", &n);
		memset(sum ,0, sizeof(sum));
		memset(tree, 0, sizeof(tree));
		memset(nodes, 0, sizeof(nodes));

		for (i = 1;i <= n; ++i)
		{
			scanf("%d", &arr[i]);
		}

		scanf("%d", &m);
		for(i = 1;i <= m; ++i)
		{
			scanf("%d %d", &nodes[i].x, &nodes[i].y);
			nodes[i].index = i;
		}

		sort(nodes + 1, nodes + m + 1, cmp);

		m_hash.clear();
		num = 1;
		for (i = 1;i <= m; ++i)
		{
			while(num <= nodes[i].y)
			{
				if(m_hash.find(arr[num]) != m_hash.end())
				{
					udpate(n, m_hash[arr[num]], -arr[num]);
				}

				m_hash[arr[num]] = num;
				udpate(n, num, arr[num]);
				
				++num;
			}

			sum[nodes[i].index] = getsum(nodes[i].y) - getsum(nodes[i].x - 1); 

		}

		for(int i=1;i<=m;++i) printf("%I64d\n",sum[i]);
	}

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值