1. 程式人生 > >bzoj 1878: [SDOI2009]HH的項鏈 ——樹狀數組+ 差分

bzoj 1878: [SDOI2009]HH的項鏈 ——樹狀數組+ 差分

cto logs pan 處理 樹狀 所表 都沒有 spa ()

Description

HH有一串由各種漂亮的貝殼組成的項鏈。HH相信不同的貝殼會帶來好運,所以每次散步 完後,他都會隨意取出一 段貝殼,思考它們所表達的含義。HH不斷地收集新的貝殼,因此他的項鏈變得越來越長。有一天,他突然提出了一 個問題:某一段貝殼中,包含了多少種不同的貝殼?這個問題很難回答。。。因為項鏈實在是太長了。於是,他只好求助睿智的你,來解決這個問題。

Input

第一行:一個整數N,表示項鏈的長度。 第二行:N個整數,表示依次表示項鏈中貝殼的編號(編號為0到1000000之間的整數)。 第三行:一個整數M,表示HH詢問的個數。 接下來M行:每行兩個整數,L和R(1 ≤ L ≤ R ≤ N),表示詢問的區間。
N ≤ 50000,M ≤ 200000。

Output

M行,每行一個整數,依次表示詢問對應的答案。

Sample Input

6
1 2 3 4 3 5
3
1 2
3 5
2 6

Sample Output

2
2
4
———————————————————————————————— 這道題我們維護一下每個點的pre[i]

即對於每個位置i,預處理出pre[i]表示i左邊離i最近的j 使得a[i]==a[j]

然後我們枚舉右端點 維護一下每個左端點的答案就可以辣

即掃到一個點i的時候 s[pre[i]]-- s[i]++ 維護一下樹狀數組的差分就行了

因為你當前往前必然包含這個點 所以前面的區間的同一顏色的位置對當前以及後面的區間都沒有任何影響了

技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
const int M=1e5+7;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<0||c>9){if(c==-) f=-1; c=getchar();}
    while(c>=0&&c<=9){ans=ans*10+(c-0); c=getchar();}
    return
ans*f; } int n,m,k; int ans[5*M],last[15*M],pre[15*M],s[M]; struct pos{int x,id;}; std::vector<pos>q[M]; int l,r; #define lowbit(x) x&-x void ins(int x,int v){while(x<=n) s[x]+=v,x+=lowbit(x);} int query(int x){ int sum=0; while(x) sum+=s[x],x-=lowbit(x); return sum; } int main(){ n=read(); for(int i=1;i<=n;i++){ k=read(); if(last[k]) pre[i]=last[k]; last[k]=i; } m=read(); for(int i=1;i<=m;i++) l=read(),r=read(),q[r].push_back((pos){l-1,i}); for(int i=1;i<=n;i++){ if(pre[i]) ins(pre[i],-1); ins(i,1); int mx=q[i].size(),now=query(i); for(int j=0;j<mx;j++){ int x=q[i][j].x; ans[q[i][j].id]=now-query(x); } } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }
View Code

bzoj 1878: [SDOI2009]HH的項鏈 ——樹狀數組+ 差分