Description
可怜有一个长度为n的正整数序列Ai,其中相同的正整数代表着相同的颜色。
现在可怜觉得这个序列太长了,于是她决定选择一些颜色把这些颜色的所有位置都删去。
删除颜色i可以定义为把所有满足Aj=i的位置j都从序列中删去。
然而有些时候删去之后,整个序列变成了好几段,可怜不喜欢这样,于是她想要知道有多
少种删去颜色的方案使得最后剩下来的序列非空且连续。
例如颜色序列{1,2,3,4,5},删除颜色3后序列变成了{1,2}和{4,5}两段,不满足条件。
而删除颜色1后序列变成了{2,3,4,5},满足条件。
两个方案不同当且仅当至少存在一个颜色i只在其中一个方案中被删去 。
Input
第一行输入一个整数T表示数据组数。
每组数据第一行输入一个整数n表示数列长度。
第二行输入n个整数描述颜色序列。
1 ≤ T, ∑ n ≤ 3 × 10^5, 1 ≤ Ai ≤ n
Output
对于每组数据输出一个整数表示答案
对每种颜色,只能全选或全不选,将区间[L,R]看作平面上的点(L,R),则限制条件是矩形内的点不能选,可以用线段树维护扫描线进行统计。
#include<bits/stdc++.h> char buf[10000007],*ptr=buf; int _(){ int x=0; while(*ptr<48)++ptr; while(*ptr>47)x=x*10+*ptr++-48; return x; } const int N=3e5+7; int T,n; int a[N],pe[N],pb[N],pv[N],nx[N]; long long ans; int min(int a,int b){return a<b?a:b;} int _l,_r,_a; struct node{ node*lc,*rc; int L,R,M; int mn,mt,a; void add(int x){ mn+=x,a+=x; } void dn(){ if(a){ lc->add(a); rc->add(a); a=0; } } void up(){ mn=min(lc->mn,rc->mn); mt=(mn==lc->mn?lc->mt:0)+(mn==rc->mn?rc->mt:0); } void add(){ if(_l<=L&&R<=_r)return add(_a); dn(); if(_l<=M)lc->add(); if(_r>M)rc->add(); up(); } int c0(){ return mn?0:mt; } }ns[N*2],*np,*rt; node*build(int L,int R){ node*w=np++; w->L=L,w->R=R; w->mn=w->a=w->M=0; w->mt=R-L+1; if(L<R){ int M=w->M=L+R>>1; w->lc=build(L,M); w->rc=build(M+1,R); } return w; } void add(int l,int r,int a){ _l=l,_r=r,_a=a; if(l<=r)rt->add(); } int main(){ fread(buf,1,sizeof(buf),stdin); for(T=_();T;--T){ n=_();ans=0; np=ns; rt=build(1,n); for(int i=1;i<=n;++i)a[i]=_(),pe[i]=0,pb[i]=n+1; for(int i=1,x;i<=n;++i)x=a[i],pv[i]=pe[x],pe[x]=i; for(int i=n,x;i>=1;--i)x=a[i],nx[i]=pb[x],pb[x]=i; add(1,n,1); for(int i=n,x;i;--i){ x=a[i]; add(i+1,nx[i]-1,1); if(i==pb[x])add(pe[x],n,-1); ans+=rt->c0(); } printf("%lld\n",ans); } return 0; }