Problem Description
Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count it once. We define the beautiful value of some interval [x,y] as F(x,y). F(x,y) is calculated as the sum of the beautiful value from the xth ball to the yth ball and the same value is ONLY COUNTED ONCE. For example, if the necklace is 1 1 1 2 3 1, we have F(1,3)=1, F(2,4)=3, F(2,6)=6.
Now Mery thinks the necklace is too long. She plans to take some continuous part of the necklace to build a new one. She wants to know each of the beautiful value of M continuous parts of the necklace. She will give you M intervals [L,R] (1<=L<=R<=N) and you must tell her F(L,R) of them.
Input
The first line is T(T<=10), representing the number of test cases.
For each case, the first line is a number N,1 <=N <=50000, indicating the number of the magic balls. The second line contains N non-negative integer numbers not greater 1000000, representing the beautiful value of the N balls. The third line has a number M, 1 <=M <=200000, meaning the nunber of the queries. Each of the next M lines contains L and R, the query.
Output
For each query, output a line contains an integer number, representing the result of the query.
Sample Input
2
6
1 2 3 4 3 5
3
1 2
3 5
2 6
6
1 1 1 2 3 5
3
1 1
2 4
3 5
Sample Output
3
7
14
1
3
6
给你一段长度为 N 的序列,然后是 M 个询问,要求计算每段区间的连续和注意:重复的元素只能在连续和中出现一次
如何消除序列中的重复的元素。 先将所有的询问记录下来,再按照询问的连续和区间的右端点由小到大排序。
可以用 map<int, int> 来记录当前元素是否出现过。前一个int 记录元素的值, 后一个 int 标记元素出现的最新下标
开始初始化 map 为空从第一个元素 index = 1 开始加入树桩数组
依次遍历排序后的询问:
如果当前元素在前面出现过, 则删除它出现在树状数组的在前面的位置。同时把它当前的位置加入树桩数组
也就是说:对于相同的元素,只使用它最后出现的位置,前面出现过的全部消除。
这样就相当于转换成求一段连续区间的序列和了,因为重复出现的元素已经消除了。
AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<stdlib.h>
#include<queue>
#include<map>
#include<iomanip>
#include<math.h>
using namespace std;
typedef long long ll;
typedef double ld;
const int maxn=50000+10;
const int maxQ=200000+10;
int i,j,k;
int a[maxn];
ll sum[maxn];
ll ans[maxQ];
map<int,int>mp;
int n,m;
struct nde
{
int left, right;
int index;
}q[maxQ];
bool cmp(nde a,nde b)
{
return a.right<b.right;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int index, int value)
{
while(index<=n)
{
sum[index] += value;
index += lowbit(index);
}
}
ll ask(int index)
{
ll ret=0;
while(index>0)
{
ret+=sum[index];
index-=lowbit(index);
}
return ret;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d", &n);
memset(a, 0, sizeof(a));
memset(sum, 0, sizeof(sum));
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
scanf("%d", &m);
for(i = 1; i <= m; i++)
{
scanf("%d %d", &q[i].left, &q[i].right);
q[i].index=i;
}
sort(q+1, q+1+m, cmp);
mp.clear(); //清空标记
int index=1; //从 1 遍历
for(i = 1; i <= m; i++)
{
while(index <= q[i].right) // 对每一次询问,一直遍历到区间的最右端
{
if(mp[a[index]] != 0) //如果前面出现过当前数字, 删除它在前面位置形成的影响
add(mp[a[index]], -a[index]);
mp[a[index]] = index; //记录新的元素值为 a[index]的位置 index
add(index, a[index]);//重新加入在当前“最后”位置形成的影响,
index++; //遍历下一个元素
}
ans[q[i].index]=ask(q[i].right)-ask(q[i].left-1); //树状数组求连续序列和
}
for(i = 1; i <= m; i++)
printf("%lld\n", ans[i]);
}
return 0;
}