HDU_3333 Turing Tree(树状数组+离线操作)
传送门: Turing Tree
题意:
给定长度为 n 的数组以及 q 次询问,每次询问给出一对 l、r,输出 [l, r] 区间上所有互不相同的元素的总和
思路:
考虑一个简化的问题,假如询问的区间右端点固定为 n,这时我们可以对原数组进行一定的处理,即只保留每个数最后一次出现的位置,其余位置清空为 0,对于某个询问区间 [i, n],其结果就等于处理后的数组在 [i,n] 上的区间和,维护一个前缀和数组 b 就可以处理所有区间询问
原问题与这个问题类似,我们可以先将所有询问区间按右端点从小到大排序(离线操作),接下来就是与简化问题相同的做法,对于所有右端点同为 r 的询问区间,维护原数组 [1, r] 上最后一次出现的数的前缀和,下一步需要的 [1, r+1] 区间的前缀和则可以由 [1,r] 转移过来,所以这里应该使用树状数组维护前缀和。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef tuple<int, int, int> tup;
#define fsio ios::sync_with_stdio(false)
#define lowbit(x) ((x)&-(x))
const int maxn = 2e5+10;
int n, q, s[maxn];
ll c[maxn], ans[maxn];
void update(int x, ll val)
{
for (; x <= n; x += lowbit(x)) c[x] += val;
}
ll query(int x)
{
ll ans = 0;
for (; x; x -= lowbit(x)) ans += c[x];
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
memset(c, 0, sizeof(c));
map<int, int> pre;
priority_queue<tup> qu;
cin>>n;
for (int i = 1; i <= n; i++) cin>>s[i];
cin>>q;
for (int i = 1; i <= q; i++)
{
int l, r;
cin>>l>>r;
qu.push(tup(-r, l, i));
}
for (int i = 1; i <= n; i++)
{
if (pre.count(s[i]))
{
update(pre[s[i]], -s[i]);
}
update(i, s[i]);
while(!qu.empty())
{
int r = get<0>(qu.top());
int l = get<1>(qu.top());
int id = get<2>(qu.top());
//auto [r, l, id] = qu.top();
r = -r;
if (r != i) break;
qu.pop();
ans[id] = query(r) - query(l-1);
}
pre[s[i]] = i;
}
for (int i = 1; i <= q; i++)
cout<<ans[i]<<endl;
}
return 0;
}