寒假刷題25:洛谷P1972 [SDOI2009]HH的項鍊(樹狀數組)

題目鏈接:

P1972 [SDOI2009]HH的項鍊

題目大意:

給你一個長爲n(n<=1e6)的數組,有m(m<=1e6)次詢問,每次詢問包含兩個整數L,R,求區間[L,R]內共有幾種不同的數字

題目解析:

對於若干個詢問的區間[l,r],如果他們的r都相等的話,那麼項鍊中出現的同一個數字,一定是隻關心出現在最右邊的那一個的,例如:

項鍊是:1 3 4 5 1

那麼,對於r=5的所有的詢問來說,第一個位置上的1完全沒有意義,因爲r已經在第五個1的右邊,對於任何查詢的[L,5]區間來說,如果第一個1被算了,那麼他完全可以用第五個1來替代。

因此,我們可以對所有查詢的區間按照r來排序,然後再來維護一個樹狀數組,這個樹狀數組是用來幹什麼的呢?看下面的例子:

1 2 1 3

對於第一個1,insert(1,1);表示第一個位置出現了一個不一樣的數字,此時樹狀數組所表示的每個位置上的數字(不是它本身的值而是它對應的每個位置上的數字)是:1 0 0 0

對於第二個2,insert(2,1);此時樹狀數組表示的每個數字是1 1 0 0

對於第三個1,因爲之前出現過1了,因此首先把那個1所在的位置刪掉insert(1,-1),然後在把它加進來insert(3,1)。此時每個數字是0 1 1 0

如果此時有一個詢問[2,3],那麼直接求sum(3)-sum(2-1)=2就是答案。

AC代碼:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
#define ll long long
const int MAXN=1000000+10;
int n,m,c[MAXN],a[MAXN];
int flag[MAXN];
struct query
{
    int l,r,num;
    int ans;
}q[MAXN];
bool mycmp(query x,query y)
{
    return x.r<y.r;
}
bool mycmp2(query x,query y)
{
    return x.num<y.num;
}
inline int lowbit(int x) {return x&-x;}
int sum(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void add(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].num=i;
    }
    sort(q+1,q+m+1,mycmp);
    for(int i=1;i<=m;i++)
    {
        for(int j=q[i-1].r+1;j<=q[i].r;j++)
        {
            if(flag[a[j]]) add(flag[a[j]],-1);
            add(j,1);
            flag[a[j]]=j;
        }
        //cout<<sum(q[i].r)<<endl;
        q[i].ans=sum(q[i].r)-sum(q[i].l-1);
    }
    sort(q+1,q+m+1,mycmp2);
    for(int i=1;i<=m;i++) printf("%d\n",q[i].ans);
}

 

發佈了56 篇原創文章 · 獲贊 22 · 訪問量 6298
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章