Arithmetic Progression

给定每个元素互不相同的序列 ,求排序后能构成等差数列的区间个数。

结论:对于元素互不相同的序列 ,其排序后是公差为 等差数列的充要条件

证明

必要性

排序后为等差数列,则 的一个排列,所以

根据辗转相减法:

充分性

不妨设

,则 ,所以 ,为等差数列。

于是问题转化为求 的区间个数。

由上面的证明不难发现 ,所以用线段树维护这个值的最小值以及最小值的个数。

每次移动右端点时,极差只需修改一个区间,但每个点的 都可能被修改。

考虑一个点作为左端点的区间 被修改的次数,发现每次修改至少会折半,所以最多修改 次,于是在线段树上暴力修改即可。

不需要 zkw 跑得也很快!

// Author:  HolyK
// Created: Wed Jul 21 12:59:35 2021
#include <bits/stdc++.h>
#define dbg(a...) fprintf(stderr, a)
template <class T, class U>
inline bool smin(T &x, const U &y) {
  return y < x ? x = y, 1 : 0;
}
template <class T, class U>
inline bool smax(T &x, const U &y) {
  return x < y ? x = y, 1 : 0;
}

using LL = long long;
using PII = std::pair<int, int>;

constexpr int N(1e5 + 5);
int n, a[N];
#define ls o << 1
#define rs o << 1 | 1
LL min[N << 2], tag[N << 2];
int cnt[N << 2], gcd[N << 2];
void pushup(int o) {
  min[o] = std::min(min[ls], min[rs]);
  cnt[o] = (min[ls] == min[o] ? cnt[ls] : 0) + (min[rs] == min[o] ? cnt[rs] : 0);
  min[o] += tag[o];
  gcd[o] = gcd[ls] == gcd[rs] ? gcd[ls] : -1;
}
void update(int o, int l, int r, int x, int y, int z) {
  if (gcd[o] > 0 && z % gcd[o] == 0) {
    min[o] -= gcd[o];
    tag[o] -= gcd[o];
    return;
  }
  if (l == r) {
    int t = gcd[o];
    gcd[o] = std::gcd(gcd[o], z);
    min[o] -= LL(gcd[o] - t) * (y - l) + gcd[o];
    cnt[o] = 1;
    return;
  }
  int m = l + r >> 1;
  if (x <= m) update(ls, l, m, x, y, z);
  if (y > m) update(rs, m + 1, r, x, y, z);
  pushup(o);
}
void add(int o, int l, int r, int x, int y, int z) {
  if (x <= l && r <= y) {
    min[o] += z;
    tag[o] += z;
    return;
  }
  int m = l + r >> 1;
  if (x <= m) add(ls, l, m, x, y, z);
  if (y > m) add(rs, m + 1, r, x, y, z);
  pushup(o);
}
int ask(int o, int l, int r, int x, int y, int z) {
  if (y < l || r < x) return 0;
  if (x <= l && r <= y) return min[o] + z == 0 ? cnt[o] : 0;
  int m = l + r >> 1;
  z += tag[o];
  return ask(ls, l, m, x, y, z) + ask(rs, m + 1, r, x, y, z);
}
int s1[N], s2[N], t1, t2; // min, max
int main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  int t;
  std::cin >> t;
  while (t--) {
    std::cin >> n;
    memset(min, 0, n + 1 << 5);
    memset(tag, 0, n + 1 << 5);
    memset(cnt, 0, n + 1 << 4);
    memset(gcd, 0, n + 1 << 4);
    for (int i = 1; i <= n; i++) {
      std::cin >> a[i];
    }
    LL ans = n;
    t1 = t2 = s1[1] = s2[1] = 1;
    for (int i = 2; i <= n; i++) {
      while (t1 && a[s1[t1]] > a[i]) {
        add(1, 1, n, s1[t1 - 1] + 1, s1[t1], a[s1[t1]]);
        t1--;
      }
      while (t2 && a[s2[t2]] < a[i]) {
        add(1, 1, n, s2[t2 - 1] + 1, s2[t2], -a[s2[t2]]);
        t2--;
      }
      add(1, 1, n, s1[t1] + 1, i, -a[i]);
      add(1, 1, n, s2[t2] + 1, i, a[i]);
      s1[++t1] = s2[++t2] = i;
      update(1, 1, n, 1, i - 1, a[i] - a[i - 1]);
      ans += ask(1, 1, n, 1, i - 1, 0);
    }
    std::cout << ans << "\n";
  }
  return 0;
}