1. 程式人生 > >洛谷——P1972 [SDOI2009]HH的項鍊(線段樹)

洛谷——P1972 [SDOI2009]HH的項鍊(線段樹)

P1972 [SDOI2009]HH的項鍊

 

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

 

莫隊的做法被卡了,所以刷一篇線段樹的做法,由於是離線,限制並不算太多

把詢問按照右端點排序,從序列左端點向右掃,進行三個操作:

$1$.將上一個與$c[i]$相同的點變為0

$2$.將這個點變為1

$3$.詢問右端點固定的區間的答案

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>

#define N 1000000
using namespace std;

struct node{
    int sum;
}tr[N];
int c[N],last[N];
struct kpde{
    int l,r,id,an;
}p[N];

bool cmp(kpde A,kpde B){
    
return A.r<B.r; } bool ccmp(kpde A,kpde B){ return A.id<B.id; } void pushup(int k){ tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum; } void change(int k,int l,int r,int X,int val){ if(l==r){ tr[k].sum=val;return; } int mid=(l+r)>>1; if(X<=mid) change(k<<1
,l,mid,X,val); else change(k<<1|1,mid+1,r,X,val); pushup(k); } int ask(int k,int l,int r,int ql,int qr){ if(l>=ql&&r<=qr) return tr[k].sum; int mid=(l+r)>>1,ans=0; if(ql<=mid) ans+=ask(k<<1,l,mid,ql,qr); if(qr>mid) ans+=ask(k<<1|1,mid+1,r,ql,qr); return ans; } int n,m; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&c[i]); scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d%d",&p[i].l,&p[i].r),p[i].id=i; sort(p+1,p+1+m,cmp); int now=1; for(int i=1;i<=n;i++){ if(last[c[i]]) change(1,1,n,last[c[i]],0); last[c[i]]=i; change(1,1,n,i,1); while(p[now].r==i){ p[now].an=ask(1,1,n,p[now].l,p[now].r); now++; } } sort(p+1,p+1+m,ccmp); for(int i=1;i<=m;i++) printf("%d\n",p[i].an); return 0; }