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;
}
posted @ 2022-07-16 19:51  Pannta  阅读(47)  评论(0编辑  收藏  举报