求一个序列中所有数字的和,其中数值相同的只能计算一次。
先储存所有的请求,然后按照它们的右边界排序,在查询的同时更新区间。这里其实有一点点DP的味道,在它进行某个查询之前,保证所有的重复数字(除去最后一个)都被删除光了,并且有不能影响其他查询,所以呢,只能从最近的那个操作进行计算。1次query即可
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 50050;
const int maxm = 200050;
vector<int> vec;
__int64 res[maxm];
__int64 ans;
int pre[1000050];
void init()
{
vec.clear();
vec.push_back(0);
memset(pre, 0, sizeof(pre));
}
struct line{
int left, right, id;
bool operator<(const line &y)const
{
return right < y.right;
}
}q[maxm];
struct node{
int left, right;
__int64 sum;
int mid(){
return (left+right)/2;
}
}tree[maxn*4];
void buildTree(int left, int right, int rt)
{
tree[rt].left = left;
tree[rt].right = right;
if(left == right){
int a;
scanf("%d", &a);
vec.push_back(a);
return ;
}
int mid = tree[rt].mid();
buildTree(left, mid, rt<<1);
buildTree(mid+1, right, rt<<1|1);
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
void update(int left, int right, int rt, int pos, int add)
{
if(left == right){
tree[rt].sum = add;
return ;
}
int mid = tree[rt].mid();
if(pos <= mid)
update(left, mid, rt<<1, pos, add);
if(pos > mid)
update(mid+1, right, rt<<1|1, pos, add);
tree[rt].sum = tree[rt<<1].sum + tree[rt<<1|1].sum;
}
void query(int left, int right, int rt, int L, int R)
{
if(L <= left && R >= right){
ans += tree[rt].sum;
return ;
}
int mid = tree[rt].mid();
if(L <= mid)
query(left, mid, rt<<1, L, R);
if(R > mid)
query(mid+1, right, rt<<1|1, L, R);
}
int main()
{
int T, M, N;
scanf("%d", &T);
while(T --)
{
scanf("%d", &N);
init();
buildTree(1, N, 1);
scanf("%d", &M);
for(int i = 1; i <= M; i ++)
{
scanf("%d%d", &q[i].left, &q[i].right);
q[i].id = i;
}
sort(q+1, q+M+1);//排序是从index=1开始的M个数
int qn = 0;
for(int i = 1; i <= N && qn <=M; i ++)
{
if(pre[vec[i]] != 0){
update(1, N, 1, pre[vec[i]], 0);
}
update(1, N, 1, i, vec[i]);
while(qn <= M && q[qn].right <= i){
ans = 0;
if(q[qn].right == i){
query(1, N, 1, q[qn].left, q[qn].right);
res[q[qn].id] = ans;
}
qn ++;
}
pre[vec[i]] = i;
}
for(int i = 1; i <= M; i ++) printf("%I64d\n", res[i]);
}
return 0;
}