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
对于每组数据输出一个整数表示答案
Sample Input
1
5
1 3 2 4 3
Sample Output
6
//满足条件的删颜色方案有 {1}, {1, 3}, {1, 2, 3}, {1, 3, 4}, {2, 3, 4}, ∅
HINT
设每种颜色出现位置的最小值和最大值为mn[i]和mx[i]。
那么题目其实就是问有多少个区间[l,r]满足max(mx[l..r])<=r且min(mn[l,r])>=l。
这个可以枚举右端点,然后用一个单调栈来维护mx,用另外一个单调栈来维护所有满足mn限制的左端点,每次只要在单调栈上二分一下即可。
CODE
#include <bits/stdc++.h>
const int N = 300005;
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int l[N],r[N];
int mx[N],mn[N];
int c[N];
int s1[N],s2[N];
int binary(int tot, int tmp)
{
int L = 1, R = tot;
while (L <= R)
{
int mid = (L + R) >> 1;
if (r[s1[mid]] > tmp)
L = mid + 1;
else R = mid - 1;
}
return s1[L - 1] + 1;
}
int main()
{
int T = read();
while (T--)
{
int n = read();
for (int i = 1; i <= n; i++)
mn[i] = n, mx[i] = 1;
for (int i = 1; i <= n; i++)
c[i] = read(), mn[c[i]] = std::min(mn[c[i]], i), mx[c[i]] = std::max(mx[c[i]], i);
for (int i = 1; i <= n; i++)
l[i] = mn[c[i]], r[i] = mx[c[i]];
long long ans = 0;
int t1 = 0, t2 = 0;
for (int i = 1; i <= n; i++)
{
while (t1 && r[s1[t1]] <= r[i])
t1--;
s1[++t1] = i;s2[++t2] = i;
while (t2 && s2[t2] > l[i])
t2--;
int lim = binary(t1, i), r = std::lower_bound(s2 + 1, s2 + t2 + 1, lim) - s2;
ans += t2 - r + 1;
}
printf("%lld\n",ans);
}
}