传送门
本题考虑固定右端点
r
r
r,然后看有多少个左端点
l
l
l符合条件。
那么如何找合法的
l
l
l呢,我们假设数组
l
a
s
t
[
a
[
r
]
]
[
0
∼
2
]
last[a[r]][0\sim 2]
last[a[r]][0∼2]分别表示元素
a
[
r
]
a[r]
a[r]在
r
r
r之前(不包括
r
r
r)最近的第一个位置、第二个位置、第三个位置。
容易得出 l l l必定位于 l a s t [ a [ r ] ] [ 2 ] + 1 ∼ l a s t [ a [ r ] ] [ 1 ] last[a[r]][2]+1\sim last[a[r]][1] last[a[r]][2]+1∼last[a[r]][1],由于 l a s t [ a [ r ] ] [ 1 ] + 1 ∼ r last[a[r]][1]+1\sim r last[a[r]][1]+1∼r区间范围内的其它数必然也会存在一个合法区间,我们要找的就是这些合法区间的交集。不妨考虑用线段树维护,对于 r r r而言我们给 l a s t [ a [ r ] ] [ 0 ] + 1 ∼ r last[a[r]][0]+1\sim r last[a[r]][0]+1∼r的区间打上 1 1 1的标记,给 l a s t [ a [ r ] ] [ 2 ] + 1 ∼ l a s t [ a [ r ] ] [ 1 ] last[a[r]][2]+1\sim last[a[r]][1] last[a[r]][2]+1∼last[a[r]][1]的区间打上 − 1 -1 −1的标记,给 1 ∼ l a s t [ a [ r ] ] [ 2 ] 1\sim last[a[r]][2] 1∼last[a[r]][2]的区间打上1的标记。我们要统计的就是权值为0的位置的个数。
为什么这样做是正确的的呢?可以这样想,对于一个位置而言,它会对合法区间作出0的总贡献,对于其它位置而言也是如此,因此所有合法区间的交集必定是权值为0的位置。用线段树维护的话我们可以类似于扫描线一样只打覆盖标记即可,不需要 p u s h d o w n pushdown pushdown,这样做得原因在于对于同一个元素而言,它对区间作出的贡献总是一段一段固定的,比如某个区间第一次被 + 1 +1 +1以后,下一次(如果后面还有这个元素)一定会被 − 1 -1 −1,并且只有当这个区间被 − 1 -1 −1以后这个区间才有机会成为合法区间,所以不必担心 p u s h d o w n pushdown pushdown的问题。
int n,last[maxn][3],t[maxn<<2],lz[maxn<<2];
void pushup(int rt,int l,int r){
if(lz[rt])t[rt]=0;
else if(l==r)t[rt]=1;
else t[rt]=t[rt<<1]+t[rt<<1|1];
}
void build(int rt,int l,int r){
if(l==r){
t[rt]=1;
return;
}
int mid=l+r>>1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt,l,r);
}
int qry(int rt,int l,int r,int x){
if(l>x)return 0;
if(r<=x)return t[rt];
int mid=l+r>>1;
return qry(rt<<1,l,mid,x)+qry(rt<<1|1,mid+1,r,x);
}
void cg(int rt,int l,int r,int ql,int qr,int val){
if(ql<=l && r<=qr){
lz[rt]+=val;
pushup(rt,l,r);
return;
}
int mid=l+r>>1;
if(ql<=mid && qr>=l)cg(rt<<1,l,mid,ql,qr,val);
if(ql<=r && qr>=mid+1)cg(rt<<1|1,mid+1,r,ql,qr,val);
pushup(rt,l,r);
}
int main(){
n=rd();
build(1,1,n);
ll ans=0;
memset(last,-1,sizeof(last));
FOR(i,1,n+1){
int u=rd();
if(last[u][0]==-1){
cg(1,1,n,1,i,1);
}else{
cg(1,1,n,last[u][0]+1,i,1);
if(last[u][1]!=-1){
if(last[u][2]==-1)cg(1,1,n,1,last[u][1],-1);
else {
cg(1,1,n,last[u][2]+1,last[u][1],-1);
cg(1,1,n,1,last[u][2],1);
}
}
}
ans+=qry(1,1,n,i);
last[u][2]=last[u][1];
last[u][1]=last[u][0];last[u][0]=i;
}
printf("%lld\n",ans);
}