题目:http://acm.hdu.edu.cn/showproblem.php?pid=3333
题意:
求一个区间内不重复数字的和,例如1 1 1 3,区间[1,4]的和为4。
分析:
我们考虑每个查询[l,r],现在要求的是这个区间里不通数的和,所以我们在从左扫到右的过程中,可以用一个数据结构保存已经得到的不同的数,到右端点后,然后对区间里不同的数求和,这样就可以得到答案了。
数据结构可以采用树状数组,那么我们是不是对每个查询区间都扫一遍呢?,显然是不行的,时间复杂度太大,我们只扫一遍即可!因为我们已经用树状数组保存了到i点之前所有的不同的数,当我们扫到某个查询区间的右端点时,我们只需要查询[l,r]这段区间即可。
当然查看是否扫到了某个右区间端点,可以先按右端点排序,或者直接用vector保存右端点相同的区间。
代码:
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int N = 1e5 + 9;
int a[N], n, q;
ll c[N], ans[N];
int lowbit (int x) {
return x & (-x);
}
void update (int x, int val) {
for (int i = x; i <= n; i += lowbit (i) )
c[i] += val;
}
ll getsum (int x) {
ll ans = 0;
for (int i = x; i >= 1; i -= lowbit (i) )
ans += c[i];
return ans;
}
ll query (int l, int r) {
return getsum (r) - getsum (l - 1);
}
struct node {
int l, id;
};
vector<node>inv[N];
map<int, int>mmap;
int main() {
//freopen("f.txt","r",stdin);
int T;
scanf ("%d", &T);
while (T-- ) {
scanf ("%d", &n);
int l, r;
for (int i = 1; i <= n; i++) scanf ("%d", &a[i]), inv[i].clear();
scanf ("%d", &q);
for (int i = 1; i <= q; i++) {
scanf ("%d%d", &l, &r);
inv[r].push_back ( (node) { l, i });
}
memset (c, 0, sizeof (c) );
mmap.clear();
for (int i = 1; i <= n; i++) {
if (mmap.count (a[i]) ) update (mmap[a[i]], -a[i]);
mmap[a[i]] = i;
update (i, a[i]);
for (int j = 0; j < inv[i].size(); j++)
ans[inv[i][j].id] = query (inv[i][j].l, i);
}
for (int i = 1; i <= q; i++)
printf ("%lld\n", ans[i]);
}
return 0;
}
/*
Sample Input
2
3
1 1 4
2
1 2
2 3
5
1 1 2 1 3
3
1 5
2 4
3 5
Sample Output
1
5
6
3
6
*/