用一个
p
r
e
[
i
]
pre[i]
pre[i] 记录当前位置颜色的前一个相同颜色的位置。
主席树维护
p
r
e
[
i
]
pre[i]
pre[i] 。
查找区间
[
0
,
l
−
1
]
[0, l-1]
[0,l−1] 。
解释
任何一个位置出现了一个颜色,那么产生贡献的区间是
[
0
,
i
−
1
]
[0,i-1]
[0,i−1]一个颜色没有出现不妨将其上一次出现的位置视为
0
0
0 ,所有在查找区间
[
l
,
r
]
[l,r]
[l,r] 内第一次出现的颜色产生的贡献在区间
[
0
,
l
−
1
]
[0,l-1]
[0,l−1] ,所以应该查找
[
0
,
l
−
1
]
[0,l-1]
[0,l−1] 。
也许有人会问比如我为什么要
r
t
[
r
]
−
r
t
[
l
−
1
]
rt[r]-rt[l-1]
rt[r]−rt[l−1]抽象化主席树的关键操作其实就是简写一下你都知道主席树了肯定知道这说的是啥 ? 因为询问区间
[
l
,
r
]
[l,r]
[l,r] 会在 区间
[
0
,
l
−
1
]
[0,l-1]
[0,l−1] 产生贡献,区间
[
1
,
l
]
[1,l]
[1,l] 也会在区间
[
0
,
l
−
1
]
[0,l-1]
[0,l−1] 产生贡献可能不是这个准确的区间但一定在这个区间内,所以我们要
r
t
[
r
]
−
r
t
[
l
−
1
]
rt[r]-rt[l-1]
rt[r]−rt[l−1] 。 Think Twice, Code Once
#include<bits/stdc++.h>#defineilinline#definegetgetchar#defineputputchar#defineisisdigit#definereregister#defineintlonglong#definedfor(i,a,b)for(re int i=a;i<=b;++i)#definedforr(i,a,b)for(re int i=a;i>=b;--i)#definedforn(i,a,b)for(re int i=a;i<=b;++i,put(10))#definemem(a,b)memset(a,b,sizeof a)#definememc(a,b)memcpy(a,b,sizeof a)#definepr114514191981#definegg(a) cout<<a,put(32)#defineINF0x7fffffff#definett(x) cout<<x<<'\n'#definelsi<<1#definersi<<1|1#definela(r) tr[r].ch[0]#definera(r) tr[r].ch[1]#definelowbit(x)(x&-x)usingnamespace std;typedefunsignedint ull;intread(void){
re int x=0,f=1;re char c=get();while(!is(c))(f=c==45?-1:1),c=get();while(is(c)) x=(x<<1)+(x<<3)+(c^48),c=get();return x*f;}voidwrite(int x){if(x<0) x=-x,put(45);if(x>9)write(x/10);put((x%10)^48);}#definewriteln(a)write(a),put(10)#definewritesp(a)write(a),put(32)#definewritessp(a)put(32),write(a)constint N=1e6+10,M=3e4+10,SN=1e4+10,mod=998244353;int n,q,cnt,rt[N],pre[N];structTR{int l,r,sum;}tr[N<<5];intmodify(int node,int l,int r,int pos){
tr[++cnt]=tr[node],++tr[cnt].sum,node=cnt;if(l==r)return node;int mid=(l+r)>>1;if(pos<=mid) tr[node].l=modify(tr[node].l,l,mid,pos);else tr[node].r=modify(tr[node].r,mid+1,r,pos);return node;}intquery(int u,int v,int l,int r,int x,int y){if(x<=l&&r<=y)return tr[v].sum-tr[u].sum;int mid=(l+r)>>1;if(y<=mid)returnquery(tr[u].l,tr[v].l,l,mid,x,y);elseif(x>mid)query(tr[u].r,tr[v].r,mid+1,r,x,y);elsereturnquery(tr[u].l,tr[v].l,l,mid,x,y)+query(tr[u].r,tr[v].r,mid+1,r,x,y);}signedmain(){
n=read();
re int u,v;dfor(i,1,n){
u=read();
rt[i]=modify(rt[i-1],0,n,pre[u]);
pre[u]=i;}
q=read();while(q--){
u=read(),v=read();writeln(query(rt[u-1],rt[v],0,n,0,u-1));}return0;}