|
|
#include <iostream>
|
|
|
#include <unordered_map>
|
|
|
#include <algorithm>
|
|
|
#include <cstdio>
|
|
|
#include <cstring>
|
|
|
|
|
|
using namespace std;
|
|
|
typedef long long LL;
|
|
|
const int N = 30010, M = 100010;
|
|
|
/*
|
|
|
图灵树的来历原来是这个。。经典的线段树离线所有查询右端点排序的题目吧。。
|
|
|
所有询问右端点排序后,从小到大扫过去,线段树维护序列区间和,用一个map记录各个数最右边出现的位置,
|
|
|
一遇到一个数就把之前位置消除并更新当前位置,相当于把各个数尽量向右移动。。
|
|
|
*/
|
|
|
struct Node {
|
|
|
int l, r;
|
|
|
LL sum;
|
|
|
} tr[N << 2];
|
|
|
|
|
|
struct Question {
|
|
|
int l, r, id;
|
|
|
const bool operator<(const Question &t) const {
|
|
|
return r < t.r;
|
|
|
}
|
|
|
} q[M];
|
|
|
|
|
|
int n, m;
|
|
|
int a[N];
|
|
|
LL ans[M];
|
|
|
|
|
|
void pushup(int u) {
|
|
|
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
|
|
|
}
|
|
|
|
|
|
void build(int u, int l, int r) {
|
|
|
tr[u] = {l, r};
|
|
|
int mid = (l + r) >> 1;
|
|
|
if (l == r) return;
|
|
|
build(u << 1, l, mid);
|
|
|
build(u << 1 | 1, mid + 1, r);
|
|
|
}
|
|
|
|
|
|
void modify(int u, int x, int d) {
|
|
|
if (tr[u].l == tr[u].r) {
|
|
|
tr[u].sum += (LL)d;
|
|
|
return;
|
|
|
}
|
|
|
int mid = (tr[u].l + tr[u].r) >> 1;
|
|
|
if (x <= mid) modify(u << 1, x, d);
|
|
|
if (x > mid) modify(u << 1 | 1, x, d);
|
|
|
pushup(u);
|
|
|
}
|
|
|
|
|
|
LL query(int u, int l, int r) {
|
|
|
if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum;
|
|
|
LL ans = 0;
|
|
|
int mid = (tr[u].l + tr[u].r) >> 1;
|
|
|
if (l <= mid) ans += query(u << 1, l, r);
|
|
|
if (r >= mid + 1) ans += query(u << 1 | 1, l, r);
|
|
|
return ans;
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
// 加快读入
|
|
|
ios::sync_with_stdio(false), cin.tie(0);
|
|
|
int T;
|
|
|
cin >> T;
|
|
|
while (T--) {
|
|
|
unordered_map<int, int> b;
|
|
|
memset(ans, 0, sizeof ans);
|
|
|
|
|
|
cin >> n;
|
|
|
for (int i = 1; i <= n; i++) cin >> a[i];
|
|
|
cin >> m;
|
|
|
|
|
|
for (int i = 1; i <= m; i++) {
|
|
|
cin >> q[i].l >> q[i].r;
|
|
|
q[i].id = i;
|
|
|
}
|
|
|
// 按右端点排序
|
|
|
sort(q + 1, q + 1 + m);
|
|
|
// 构建线段树
|
|
|
build(1, 1, n);
|
|
|
|
|
|
for (int i = 1, j = 1; i <= m; i++) { // i枚举每个查询,j枚举的是原始数组数据
|
|
|
while (j <= q[i].r) { // 在空间内的逐个进入,并不断修改最后的值
|
|
|
if (b.count(a[j])) modify(1, b[a[j]], -a[j]);
|
|
|
modify(1, j, a[j]);
|
|
|
b[a[j]] = j++;
|
|
|
}
|
|
|
ans[q[i].id] = query(1, q[i].l, q[i].r);
|
|
|
}
|
|
|
for (int i = 1; i <= m; i++) printf("%lld\n", ans[i]);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|