标签:
思路:既然要求的是不同的元素的和,那么我们可以想办法让每个值在区间中只出现一次,于是想到了离线的算法:将查询按照右端点排序,位置在右端点之前的元素都插入到树状数组中,对于已经出现过的值,我们要先删除(在原位置)再插入(在cur的位置),因为很显然对于同一个元素,只有在最靠右的位置出现一次才能返回正确的查询结果。所以我们需要用map来记录每个值上一次插入的位置,删除后再插入到当前位置。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstring> 4 #include <cstdio> 5 #include <map> 6 using namespace std; 7 8 typedef long long ll; 9 const int N = 30001; 10 const int Q = 100001; 11 ll c[N]; 12 ll ans[Q]; 13 int a[N]; 14 15 struct Query 16 { 17 int i, j, id; 18 bool operator < ( const Query & o ) const 19 { 20 return j < o.j; 21 } 22 } query[Q]; 23 24 map<int, int> mp; 25 26 int lb( int i ) 27 { 28 return i & -i; 29 } 30 31 void update( int i, int v ) 32 { 33 while ( i < N ) 34 { 35 c[i] += v; 36 i += lb(i); 37 } 38 } 39 40 ll get( int i ) 41 { 42 ll ans = 0; 43 while ( i ) 44 { 45 ans += c[i]; 46 i -= lb(i); 47 } 48 return ans; 49 } 50 51 int main () 52 { 53 int t; 54 scanf("%d", &t); 55 while ( t-- ) 56 { 57 int n, q; 58 scanf("%d", &n); 59 for ( int i = 1; i <= n; i++ ) 60 { 61 scanf("%d", a + i); 62 } 63 scanf("%d", &q); 64 for ( int i = 1; i <= q; i++ ) 65 { 66 scanf("%d%d", &query[i].i, &query[i].j); 67 query[i].id = i; 68 } 69 sort( query + 1, query + 1 + q ); 70 memset( c, 0, sizeof(c) ); 71 mp.clear(); 72 int cur = 1; 73 for ( int i = 1; i <= q; i++ ) 74 { 75 while ( cur <= query[i].j ) 76 { 77 if ( mp.count(a[cur]) ) 78 { 79 int pos = mp[a[cur]]; 80 update( pos, -a[cur] ); 81 } 82 update( cur, a[cur] ); 83 mp[a[cur]] = cur; 84 cur++; 85 } 86 ans[query[i].id] = get( query[i].j ) - get( query[i].i - 1 ); 87 } 88 for ( int i = 1; i <= q; i++ ) 89 { 90 printf("%I64d\n", ans[i]); 91 } 92 } 93 return 0; 94 }
标签:
原文地址:http://www.cnblogs.com/huoxiayu/p/4687224.html