1. 程式人生 > >BZOJ_2743_[HEOI2012]采花_離線+樹狀數組

BZOJ_2743_[HEOI2012]采花_離線+樹狀數組

-i highlight 離我 她有 bzoj 編程 連續 以及 pos

BZOJ_2743_[HEOI2012]采花_離線+樹狀數組

Description

蕭蕓斕是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。


分析:

看起來莫隊可做,但數據範圍就是為了卡這個的,於是我們考慮同樣是離線的另一種做法。

首先對於每個花,求出下一次出現顏色相同的花的位置$nxt[]$ ,如果沒有則$nxt[]$ 為0。

然後把詢問搞下來,按詢問的左端點升序排序。

一開始,我只計算每個花第一次出現時的貢獻。

掃一遍數組,假設我當前在$i$ 這個位置,離我最近的詢問左端點是$j$ ,那我們要舍棄掉$i$ 到$j-1$ 這部分的貢獻。

刪除第$i$ 個數,對右端點在$i+1\thicksim nxt[i]-1$ 的這些需要$-1$ ,對右端點在$nxt[i]\thicksim nxt[nxt[i]]-1$ 的這部分$+1$ ,然後樹狀數組維護一下整個操作即可。

代碼:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
using namespace std;
#define N 1000050
int n,v[N],c,m,b[N],nxt[N],now[N],ans[N];
struct A {
    int l,r,pos;
}a[N];
bool cmp(const A &x,const A &y) {
    if(x.l==y.l) return x.r<y.r;
    return x.l<y.l;
}
void fix(int x,int v) {
    for(;x<=n;x+=x&(-x)) b[x]+=v;
}
int inq(int x) {
    int re=0;
    for(;x;x-=x&(-x)) re+=b[x];
    return re;
}
int main() {
    scanf("%d%d%d",&n,&c,&m);
    int i;
    for(i=1;i<=n;i++) scanf("%d",&v[i]);
    for(i=1;i<=m;i++) {
        scanf("%d%d",&a[i].l,&a[i].r); a[i].pos=i;
    }
    sort(a+1,a+m+1,cmp);
    for(i=n;i;i--) {
        nxt[i]=now[v[i]]; now[v[i]]=i;
    }
    for(i=1;i<=n;i++) {
        if(nxt[i]) fix(nxt[i],1);
        if(nxt[nxt[i]]) fix(nxt[nxt[i]],-1);
    }
    int fafa=1;
    for(i=1;i<=m;i++) {
        while(fafa<a[i].l) {
            if(nxt[fafa]) fix(nxt[fafa],-1);
            if(nxt[nxt[fafa]]) fix(nxt[nxt[fafa]],1);
            fafa++;
        }
        ans[a[i].pos]=inq(a[i].r)-inq(a[i].l-1);
    }
    for(i=1;i<=m;i++) printf("%d\n",ans[i]);
}

BZOJ_2743_[HEOI2012]采花_離線+樹狀數組