Turing Tree HDU
阿新 • • 發佈:2018-12-15
題解
題目大意 給你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;
}