题目大意:
询问区间内不同种类的数的数值之和
这里逐个添加最后在线查询,会因为相同的数在区间内导致冲突
我们总是希望之后添加的数不会影响前面,那么我们就在添加到第i个数的时候,把所有在1~i 的区间的询问全部处理完成即可
对于之前的冲突,我们可以不断记录上一次冲突的位置,给当前的前缀和添加一个当前的val
对于上一次之前的前缀和要减去那个val就不会产生冲突了(之所以离线也是因为这个地方,如果后面的数添加完成,那么之前可能减去那个位置的数就导致区间查询出错)
所以将询问区间优先右排序就行了
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <map> 6 using namespace std; 7 8 #define LL long long 9 #define lowbit(x) x&(-x) 10 #define M 100010 11 #define N 30005 12 char s[6]; 13 int n , m , a[N]; 14 LL sum[N] ; 15 map<int ,int> mp; 16 17 struct Query{ 18 int l , r , id; 19 bool operator<(const Query &m) const{ 20 return r<m.r || (r==m.r&&l<m.l); 21 } 22 }qu[M]; 23 24 LL rec[M]; 25 26 void add(int x , int v) 27 { 28 while(x<=n){ 29 sum[x] = sum[x]+v ; 30 x+=lowbit(x); 31 } 32 } 33 34 LL query(int x){ 35 LL ret = 0; 36 while(x>0) ret = ret+sum[x] , x-=lowbit(x); 37 return ret; 38 } 39 40 int main() 41 { 42 //freopen("in.txt" , "r" , stdin); 43 int T ; 44 scanf("%d" , &T); 45 while(T--){ 46 scanf("%d" , &n); 47 memset(sum , 0 , sizeof(sum)); 48 for(int i=1 ; i<=n ; i++) 49 scanf("%d" , &a[i]); 50 51 scanf("%d" , &m); 52 for(int i=0 ; i<m ; i++){ 53 int l , r; 54 scanf("%d%d" , &l , &r); 55 qu[i] = (Query){l , r , i}; 56 } 57 sort(qu , qu+m); 58 int cur = 0; 59 mp.clear(); 60 for(int i=1 ; i<=n ; i++){ 61 if(mp.find(a[i]) == mp.end()){ 62 add(i , a[i]); 63 mp.insert(make_pair(a[i] , i)); 64 }else{ 65 add(i , a[i]); 66 add(mp[a[i]] , -a[i]); 67 mp[a[i]] = i; 68 } 69 while(qu[cur].r == i){ 70 rec[qu[cur].id] = query(qu[cur].r)-query(qu[cur].l-1); 71 cur++; 72 } 73 } 74 for(int i=0 ; i<m ; i++) printf("%I64d " , rec[i]); 75 } 76 return 0; 77 }