bzoj 2743: [HEOI2012]採花(樹狀數組)附加HH項鍊

首先先做HH項鍊
題目描述
HH 有一串由各種漂亮的貝殼組成的項鍊。HH 相信不同的貝殼會帶來好運,所以每次散步完後,他都會隨意取出一段貝殼,思考它們所表達的含義。HH 不斷地收集新的貝殼,因此,他的項鍊變得越來越長。

有一天,他突然提出了一個問題:某一段貝殼中,包含了多少種不同的貝殼?這個問題很難回答…… 因爲項鍊實在是太長了。於是,他只好求助睿智的你,來解決這個問題。

輸入格式
一行一個正整數 n,表示項鍊長度。
第二行 n 個正整數 ai,表示項鍊中第 i 個貝殼的種類。

第三行一個整數 m,表示詢問的個數。
接下來 m 行,每行兩個整數 l,r,表示詢問的區間。

輸出格式
輸出 m 行,每行一個整數,依次表示詢問對應的答案。

輸入輸出樣例
輸入 #1 複製
6
1 2 3 4 3 5
3
1 2
3 5
2 6
輸出 #1 複製
2
2
4
我們思考一下,如果我們對所有的右端點區間進行排序,然後按順序來計算。然後每一次詢問維持一個線段樹,這樣做的目的就是可以按照順序維護線段樹。**把線段數組當做普通的數組來看待其實非常好處理!**我們可以用book[i]表示i這朵花最後一次出現的位置,爲什麼這麼做?因爲我們從位置pos1到n遍歷,對於出現過的花,其實只有最後一次出現位置的花有意義,就好比數據12412,對於右區間爲4的詢問來說,此時對於花1來說,我們只需要把1處的花的標記消掉(怎麼消掉,只需在這個位置加上-1就能消掉了),然後在4這個位置標記一下這裏出現了一朵花就可以了。
在這裏插入圖片描述

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int top[1000010];
int num[1000010];
int book[1000010];
int answer[1000010];
struct node
{
    int l,r,pos;
}data[1000010];
bool cmp(struct node a,struct node b)
{
    return a.r<b.r;
}
int lowbit(int x)
{
    return x&(-x);
}
void updata(int i,int num)
{
    for(int j=i;j<=n;j=j+lowbit(j))
    {
        top[j]+=num;
    }
    return;
}
int getsum(int i)
{
    int ans=0;
    for(int j=i;j>0;j=j-lowbit(j))
    {
        ans+=top[j];
    }
    return ans;
}
int main ()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num[i]);
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&data[i].l,&data[i].r);
        data[i].pos=i;
    }
    sort(data+1,data+1+m,cmp);
    int j=1;
    for(int i=1;i<=n;i++)
    {
        if(!book[num[i]])//沒有出現過
        {
            book[num[i]]=i;
            updata(i,1);
        }
        else
        {
            updata(book[num[i]],-1);
            updata(i,1);
            book[num[i]]=i;
        }
        while(data[j].r==i)
        {
            answer[data[j].pos]=getsum(data[j].r)-getsum(data[j].l-1);
            j++;
        }
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d\n",answer[i]);
    }
    return 0;
}

蕭芸斕是Z國的公主,平時的一大愛好是採花。今天天氣晴朗,陽光明媚,公主清晨便去了皇宮中新建的花園採花
。花園足夠大,容納了n朵花,花有c種顏色(用整數1-c表示),且花是排成一排的,以便於公主採花。公主每次
採花後會統計採到的花的顏色數,顏色數越多她會越高興!同時,她有一癖好,她不允許最後自己採到的花中,某
一顏色的花只有一朵。爲此,公主每採一朵花,要麼此前已採到此顏色的花,要麼有相當正確的直覺告訴她,她必
能再次採到此顏色的花。由於時間關係,公主只能走過花園連續的一段進行採花,便讓女僕福涵潔安排行程。福涵
潔綜合各種因素擬定了m個行程,然後一一向你詢問公主能採到多少朵花(她知道你是編程高手,定能快速給出答
案!),最後會選擇令公主最高興的行程(爲了拿到更多獎金!)。
Input
第一行四個空格隔開的整數n、c以及m。
接下來一行n個空格隔開的整數,每個數在[1, c]間,第i個數表示第i朵花的顏色。
接下來m行每行兩個空格隔開的整數l和r(l ≤ r),表示女僕安排的行程爲公主經過第l到第r朵花進行採花。
Output
共m行,每行一個整數,第i個數表示公主在女僕的第i個行程中能採到的花的顏色數。
Sample Input
5 3 5
1 2 2 3 1
1 5
1 2
2 2
2 3
3 5
Sample Output
2
0
0
1
0
【樣例說明】
詢問[1, 5]:公主採顏色爲1和2的花,由於顏色3的花只有一朵,公主不採;詢問[1, 2]:顏色1和顏色2的花均只有一朵,公主不採;
詢問[2, 2]:顏色2的花只有一朵,公主不採;
詢問[2, 3]:由於顏色2的花有兩朵,公主採顏色2的花;
詢問[3, 5]:顏色1、2、3的花各一朵,公主不採。
Hint
【數據範圍】

對於100%的數據,1 ≤ n ≤ 10^6,c ≤ n,m ≤10^6。
基本思路都是一樣的,這次在book數組基礎上加一個pre數組就可以了。book[i]表示i這種花最後出現的位置,pre[i]表示i這種花倒數第二次出現的位置,這樣就可以處理了。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int top[1000010];
int num[1000010];
int book[1000010];//記錄數字num[i]的前一個位置
int pre[1000010];//記錄num[i]這個數的前一個位置
int answer[1000010];
struct node
{
    int l,r,pos;
}data[1000010];
bool cmp(struct node a,struct node b)
{
    return a.r<b.r;
}
int lowbit(int x)
{
    return x&(-x);
}
void updata(int i,int num)
{
    for(int j=i;j<=n;j=j+lowbit(j))
    {
        top[j]+=num;
    }
    return;
}
int getsum(int i)
{
    int ans=0;
    for(int j=i;j>0;j=j-lowbit(j))
    {
        ans+=top[j];
    }
    return ans;
}
int main ()
{
    int temp,m;
    scanf("%d%d%d",&n,&temp,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num[i]);
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&data[i].l,&data[i].r);
        data[i].pos=i;
    }
    sort(data+1,data+1+m,cmp);
    int j=1;
    for(int i=1;i<=n;i++)
    {
        if(pre[num[i]])//出現過
        {
            updata(pre[num[i]],-1);
            updata(book[num[i]],1);
            pre[num[i]]=book[num[i]];
            book[num[i]]=i;
        }
        else if(book[num[i]])
        {
            updata(book[num[i]],1);
            pre[num[i]]=book[num[i]];
            book[num[i]]=i;
        }
        else book[num[i]]=i;
        while(data[j].r==i)
        {
            answer[data[j].pos]=getsum(data[j].r)-getsum(data[j].l-1);
            j++;
        }
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d\n",answer[i]);
    }
    return 0;
}

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