#include #include #include #include #include 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 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; }