計算區間不同數的和(離線+樹狀數組)

計算區間不同數的和(離線+樹狀數組)

題目傳送門:牛客練習賽52-B:Galahad

題意:

給一個長度爲n的數組,有q次詢問,每次詢問一個區間[l,r][l,r]​ ,問這個區間的和,但如果某一個數在這個區間出現了多次,這個數只能被計算一次。

思路:

題目中只有修改操作,所以我們可以離線處理。

我們讓所有查詢按右端點從小到大排序。對於每個區間將未添加的原數組元素設爲w[p]w[p],如果 w[p]w[p] 在前面已經出現過,那就讓前面的刪除。讓p這個位置的值變爲w[p]w[p]。最後對於這個區間求區間合即可。

這樣的話區間中出現相同的數只有最後出現位置纔有貢獻。且有這個數必可以計算出貢獻。

#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int N=5e5+20;
const int mod=1e9+7;
int vis[N];
struct Seqment
{
    int l,r,id;
    bool operator < (const Seqment & o) const
    {
         return r<o.r;
    }
} seq[N];
struct TreeArray
{
    int MXN;
    ll bt[N];
    int lowbit(int k)
    {
        return k&-k;
    }
    void modify(int k,ll val)
    {
        while(k<=MXN)
        {
            bt[k]+=val;
            k+=lowbit(k);
        }
    }
    ll getpre(int k)
    {
        ll sum=0;
        while(k)
        {
            sum+=bt[k];
            k-=lowbit(k);
        }
        return sum;
    }
    ll getsum(int l,int r)
    {
        return getpre(r)-getpre(l-1);
    }

}solve;
ll w[N],res[N];
int main()
{
//    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int n,m;
    scanf("%d%d",&n,&m);
    solve.MXN=n;
    for(int i=1;i<=n;++i){
            scanf("%lld",&w[i]);
//        cin>>w[i];
    }
    for(int i=1;i<=m;++i){
        scanf("%d%d",&seq[i].l,&seq[i].r);
        seq[i].id=i;
    }
    sort(seq+1,seq+m+1);
    int p=0;
    for(int i=1;i<=m;++i)
    {
        while(p+1<=seq[i].r){
            ++p;
            if(vis[w[p]]!=0){
                solve.modify(vis[w[p]],-w[p]);
            }
            vis[w[p]]=p;
            solve.modify(p,w[p]);
        }
        res[seq[i].id]=solve.getsum(seq[i].l,seq[i].r);
    }
    for(int i=1;i<=m;++i){
        printf("%lld\n",res[i]);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章