1. 程式人生 > >Turing Tree HDU

Turing Tree HDU

題解

題目大意 給你n個數字 問你區間內不同元素的和

將訊問離線處理 按照右端點排序 遍歷每個位置用一個數組記錄每個數值的出現 如果沒出現過則線上段樹中出現位置標記出現 如果出現則刪除上次線段樹中的標記並更新標記 對於每個查詢當遍歷到查詢右端點時區間求和則為答案

AC程式碼

#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAXN = 3e4 + 10;
const int MAXQ =
1e5 + 10; int a[MAXN], vis[MAXN]; ll ans[MAXQ]; vector<int> dz; struct node2 { int l, r; int num; bool operator < (const node2 &oth) { return this->r < oth.r; } }q[MAXQ]; struct node { int l, r; ll v; }tre[MAXN * 4]; inline void PushUp(int x) { tre[x].v = tre[x <<
1].v + tre[x << 1 | 1].v; } void Build(int x, int l, int r) { tre[x].l = l, tre[x].r = r, tre[x].v = 0; if (l == r) return; else { int m = l + r >> 1; Build(x << 1, l, m); Build(x << 1 | 1, m + 1, r); } } void Update(int x, int p, ll v) { int l = tre[x].l, r = tre[
x].r; if (l == r) tre[x].v += v; else { int m = l + r >> 1; if (m >= p) Update(x << 1, p, v); else Update(x << 1 | 1, p, v); PushUp(x); } } ll Query(int x, int pl, int pr) { int l = tre[x].l, r = tre[x].r; if (pl <= l && r <= pr) return tre[x].v; else { int m = l + r >> 1; ll v = 0; if (m >= pl) v += Query(x << 1, pl, pr); if (m < pr) v += Query(x << 1 | 1, pl, pr); return v; } } int Dis(int v) { return lower_bound(dz.begin(), dz.end(), v) - dz.begin(); } int main() { #ifdef LOCAL freopen("C:/input.txt", "r", stdin); #endif int T; cin >> T; while (T--) { memset(vis, 0, sizeof(vis)); dz.clear(); dz.push_back(-INF); int N, Q; cin >> N; for (int i = 1; i <= N; i++) scanf("%d", &a[i]), dz.push_back(a[i]); sort(dz.begin(), dz.end()); dz.erase(unique(dz.begin(), dz.end()), dz.end()); //離散化值 cin >> Q; for (int i = 1; i <= Q; i++) scanf("%d%d", &q[i].l, &q[i].r), q[i].num = i; sort(q + 1, q + Q + 1); Build(1, 1, N); int j = 1; for (int i = 1; i <= N; i++) //遍歷數列 { int k = vis[Dis(a[i])]; if (k) //出現過 Update(1, k, -a[i]); //取消上次出現位置標記 Update(1, i, a[i]); //在當前位置標記新數字的值 vis[Dis(a[i])] = i; while (j <= Q && q[j].r == i) //答案右端點等於當前位置 ans[q[j].num] = Query(1, q[j].l, i), j++; //查詢區間和 } for (int i = 1; i <= Q; i++) printf("%lld\n", ans[i]); } return 0; }