相当于求满足在子段中出现的颜色只在该子段中出现的非空子段数量。这也就相当于其中出现的颜色最左出现的位置在左端点右侧,最右出现的位置在右端点左侧。那么若固定某个端点,仅考虑对该端点的限制,会有一段合法区间。这个区间可以二分+st表求出。于是枚举右端点,在其合法区间内查询有多少个合法左端点(即合法区间包括该右端点),上主席树即可。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long long #define N 300010 char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int T,n,a[N],root[N],head[N],tail[N],l[N],r[N],f[N][20],lg2[N],cnt; struct data{int l,r,x; }tree[N<<5]; int query(int l,int r) { if (l>r) return N; return min(f[l][lg2[r-l+1]],f[r-(1<<lg2[r-l+1])+1][lg2[r-l+1]]); } int query2(int l,int r) { if (l>r) return -1; return max(f[l][lg2[r-l+1]],f[r-(1<<lg2[r-l+1])+1][lg2[r-l+1]]); } void ins(int &k,int l,int r,int x) { tree[++cnt]=tree[k],k=cnt;tree[k].x++; if (l==r) return; int mid=l+r>>1; if (x<=mid) ins(tree[k].l,l,mid,x); else ins(tree[k].r,mid+1,r,x); } int query(int x,int y,int l,int r,int p,int q) { if (!y) return 0; if (l==p&&r==q) return tree[y].x-tree[x].x; int mid=l+r>>1; if (q<=mid) return query(tree[x].l,tree[y].l,l,mid,p,q); else if (p>mid) return query(tree[x].r,tree[y].r,mid+1,r,p,q); else return query(tree[x].l,tree[y].l,l,mid,p,mid)+query(tree[x].r,tree[y].r,mid+1,r,mid+1,q); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj5011.in","r",stdin); freopen("bzoj5011.out","w",stdout); const char LL[]="%I64d "; #else const char LL[]="%lld "; #endif T=read(); while (T--) { n=read(); for (int i=1;i<=n;i++) a[i]=read(),head[i]=n+1,tail[i]=0; for (int i=1;i<=n;i++) head[a[i]]=min(head[a[i]],i),tail[a[i]]=max(tail[a[i]],i); lg2[1]=0; for (int i=2;i<=n;i++) { lg2[i]=lg2[i-1]; if ((2<<lg2[i])<=i) lg2[i]++; } for (int i=1;i<=n;i++) f[i][0]=head[a[i]]; for (int j=1;j<20;j++) for (int i=1;i<=n;i++) f[i][j]=min(f[i][j-1],f[min(n,i+(1<<j-1))][j-1]); for (int i=1;i<=n;i++) { int L=i-1,R=n; while (L<=R) { int mid=L+R>>1; if (query(i,mid)>=i) l[i]=mid,L=mid+1; else R=mid-1; } } for (int i=1;i<=n;i++) f[i][0]=tail[a[i]]; for (int j=1;j<20;j++) for (int i=1;i<=n;i++) f[i][j]=max(f[i][j-1],f[min(n,i+(1<<j-1))][j-1]); for (int i=1;i<=n;i++) { int L=1,R=i+1; while (L<=R) { int mid=L+R>>1; if (query2(mid,i)<=i) r[i]=mid,R=mid-1; else L=mid+1; } } root[0]=0; for (int i=1;i<=n;i++) { root[i]=root[i-1]; ins(root[i],1,n,l[i]); } ll ans=0; for (int i=1;i<=n;i++) ans+=query(root[r[i]-1],root[i],1,n,i,n); printf(LL,ans); } return 0; }