← Home
```go
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
	"strconv"
)

func min(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func max(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	scanner.Split(bufio.ScanWords)
	buf := make([]byte, 1024*1024)
	scanner.Buffer(buf, 10*1024*1024)

	nextInt64 := func() int64 {
		scanner.Scan()
		v, _ := strconv.ParseInt(scanner.Text(), 10, 64)
		return v
	}

	nextInt := func() int {
		scanner.Scan()
		v, _ := strconv.Atoi(scanner.Text())
		return v
	}

	writer := bufio.NewWriter(os.Stdout)
	defer writer.Flush()

	if !scanner.Scan() {
		return
	}
	t, _ := strconv.Atoi(scanner.Text())

	for ; t > 0; t-- {
		n := nextInt()
		a := make([]int64, n)
		for i := 0; i < n; i++ {
			a[i] = nextInt64()
		}

		A := make([]int64, n+1)
		A[0] = 0
		for i := 1; i <= n; i++ {
			if i%2 == 1 {
				A[i] = A[i-1] - a[i-1]
			} else {
				A[i] = A[i-1] + a[i-1]
			}
		}

		minTree := make([]int64, 4*(n+1))
		maxTree := make([]int64, 4*(n+1))
		const INF int64 = 3e18
		const NINF int64 = -3e18

		var build func(node, l, r int)
		build = func(node, l, r int) {
			if l == r {
				if l%2 == 0 {
					minTree[node] = A[l]
					maxTree[node] = NINF
				} else {
					minTree[node] = INF
					maxTree[node] = A[l]
				}
				return
			}
			mid := (l + r) / 2
			build(2*node, l, mid)
			build(2*node+1, mid+1, r)
			minTree[node] = min(minTree[2*node], minTree[2*node+1])
			maxTree[node] = max(maxTree[2*node], maxTree[2*node+1])
		}
		build(1, 0, n)

		var queryMin func(node, l, r, ql, qr int, val int64) int
		queryMin = func(node, l, r, ql, qr int, val int64) int {
			if l > qr || r < ql || minTree[node] >= val {
				return -1
			}
			if l == r {
				return l
			}
			mid := (l + r) / 2
			res := queryMin(2*node, l, mid, ql, qr, val)
			if res != -1 {
				return res
			}
			return queryMin(2*node+1, mid+1, r, ql, qr, val)
		}

		var queryMax func(node, l, r, ql, qr int, val int64) int
		queryMax = func(node, l, r, ql, qr int, val int64) int {
			if l > qr || r < ql || maxTree[node] <= val {
				return -1
			}
			if l == r {
				return l
			}
			mid := (l + r) / 2
			res := queryMax(2*node, l, mid, ql, qr, val)
			if res != -1 {
				return res
			}
			return queryMax(2*node+1, mid+1, r, ql, qr, val)
		}

		sortedA := make([]int64, n+1)
		copy(sortedA, A)
		sort.Slice(sortedA, func(i, j int) bool { return sortedA[i] < sortedA[j] })
		var unq []int64
		for i := 0; i <= n; i++ {
			if i == 0 || sortedA[i] != sortedA[i-1] {
				unq = append(unq, sortedA[i])
			}
		}

		getID := func(val int64) int {
			l, r := 0, len(unq)-1
			for l <= r {
				mid := (l + r) / 2
				if unq[mid] == val {
					return mid
				} else if unq[mid] < val {
					l = mid + 1
				} else {
					r = mid - 1
				}
			}
			return -1
		}

		pos := make([][]int, len(unq))
		for i, v := range A {
			id := getID(v)
			pos[id] = append(pos[id], i)
		}

		var total int64 = 0
		for i := 0; i <= n; i++ {
			val := A[i]
			lim1 := n + 1
			if i < n {
				r1 := queryMin(1, 0, n, i+1, n, val)
				if r1 != -1 {
					lim1 = r1
				}
			}
			lim2 := n + 1
			if i < n {
				r2 := queryMax(1, 0, n, i+1, n, val)
				if r2 != -1 {
					lim2 = r2
				}
			}
			lim := lim1
			if lim2 < lim {
				lim = lim2
			}

			id := getID(val)
			indices := pos[id]
			leftIdx := sort.Search(len(indices), func(k int) bool { return indices[k] > i })
			rightIdx := sort.Search(len(indices), func(k int) bool { return indices[k] >= lim })
			total += int64(rightIdx - leftIdx)
		}

		fmt.Fprintln(writer, total)
	}
}
```