HDU3874 树状数组的灵活应用

来源:互联网 发布:软件外包开发协议 编辑:程序博客网 时间:2024/06/06 02:05

给一个序列,查询任意一段的和。一段中重复的数不算。

看见这个题的第一想法是线段树,用线段树进行查询操作,这个肯定是可以的。

刚才看见这个题的另外一种解法,一种树状数组的离线算法。很好很强大。用map记录当前值是否出现过,并记录这个值的最后一处的位置,当遍历到某个值时,如果前面已经出现过,那么将前面那个数的值清为0,即将map记录的这个数的位置上的数减去这个数,当前位置插入这个值。离线处理询问即可。

代码:

#include <cstdio>#include <cstring>#include <map>#include <algorithm>using namespace std;const int N = 50010;int n, m, a[N];map<int, int> hash;long long ans[N*4],su[4*N];struct node{int i, l, r;} q[N*4];void update(int i, int v){while(i <= n){su[i] += v;i += i&(-i);}}long long query(int i){long long sum = 0;while(i > 0){sum += su[i];i -= i&(-i);}return sum;}int cmp1(node a, node b){return a.r < b.r;}int main(){int cas, i, j, k, l, r;scanf("%d", &cas);while(cas--){scanf("%d", &n);for(i = 1; i <= n; i++)scanf("%d", &a[i]);scanf("%d", &m);for(i = 0; i < m; i++){scanf("%d%d", &q[i].l, &q[i].r);if(q[i].l > q[i].r)swap(q[i].l, q[i].r);q[i].i = i;}sort(q, q+m, cmp1);hash.clear();r = 1;memset(su,0,sizeof(su));for(i = 0; i < m; i++){while(r <= q[i].r){if(hash[a[r]] != 0)update(hash[a[r]], -a[r]);hash[a[r]] = r;update(r, a[r]);r++;}ans[q[i].i] = query(q[i].r) - query(q[i].l-1);}for(i = 0; i < m; i++)printf("%I64d\n", ans[i]);}return 0;}