// ConsoleApplication1.cpp : このファイルには 'main' 関数が含まれています。プログラム実行の開始と終了がそこで行われます。
//

//#include "pch.h"

#include <iostream>
#include <cmath>
#include <climits>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <string>
#include <stack>
#include <algorithm>
#include <map>
#include <numeric>
#include <set>
#include <queue>
#include <sstream>
#include <bitset>
using namespace std;

#define ll long long
#define ld long double
#define pi 3.14159265359;
// %llu %lf

// ■v:vector  type:型  order:greater(大きい順) or less(小さい順)
#define _sort(v,type,order) do { sort(v.begin(),v.end(),order<type>()); } while(0)
// ■vector 要素の総和算出
// v:vector  default_value:初期値
#define _sum(v,default_value) accumulate(v.begin(),v.end(),default_value )
// ■vector 最大値( return ite )
#define _max_element(v) max_element(v.begin(),v.end())
// ■vector 最小値( return ite )
#define _min_element(v) min_element(v.begin(),v.end())
// ■vector 最大値が格納されている要素値
#define _max_element_number(v) distance(v.begin(),max_element(v.begin(),v.end()))
// ■特定コンテナの中から特定の値をカウントする
#define _count(v,value) count(v.begin(),v.end(),value)

//set<uint32_t> member;	// 重複するデータを保持する事はできない member.insert(2) member.insert(2) ⇒ member.count(2)は1
//                                                              member.emplace(2)とかも同じ
//multiset<uint32_t> v;	// 重複するデータも保持する事はできる   member.insert(2) member.insert(2) ⇒ member.count(2)は2

// ■丸め
#define _round(v)  round(v)
// ■2乗 / 3乗
#define _square(v) pow(v,2)
#define _cube(v)   pow(v,3)
// ■大小判定
#define _max(x,y)  max(x,y)
#define _min(x,y)  min(x,y)
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; }return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; }return false; }
// ■string ⇒ int
#define _stringtoi(s) stoi(s)
// ■double 平方根
#define _sqrt(x) sqrt(x)
// ■double 引数 x 以上で最小の整数値 ex) 3.30303 ⇒ 4
#define _ceil(x) ceil(x)
// ■指定された要素以上の値が現れる最初の位置のイテレータを取得する
#define _lower_bound(v,min) lower_bound(v.begin(), v.end(), min)
// ■指定された要素より大きい値が現れる最初の位置のイテレータを取得する
#define _upper_bound(v,min) upper_bound(v.begin(), v.end(), min)

// ■数列の組合せ
// 順列 n個の数が与えられる
// 0,1,2,...,n-1
// 全ての並べ方を1行ごとに出力する
// vector<> v = { 0 , 1 , 2 };
// ex 0 1 2 / 0 2 1 / 1 0 2 / 1 2 0 / 2 0 1 / 2 1 0
/*
例えば、順列 {2, 1, 3} が与えられらた場合は、その次の順番の順列 {2, 3, 1} を生成する。
一番最後の順列 {3, 2, 1} が与えられた場合は、一番最初の順列 {1, 2, 4} を生成する。
next_permutation() は最後から最初の順列を生成した場合のみ false を返し、それ以外の場合は true を返す。
なので、全順列を生成する場合には、最初に要素を【昇順】に並べておき、do - while ループで、
next_permutation() がfalse を返すまでループさせる。
*/
#define _next_permutation(v) do {   \
	for (auto num : v) {            \
		printf("%d ", num);         \
	}                               \
	printf("\n");                   \
} while (next_permutation(v.begin(), v.end()))

// ■bitset
// 100 桁の 2 進数を定義する。
// bitset<100> bs;
// 
// 8桁 の 2進数を定義し、10進数 131で初期化
// bitset<8> bs(131);			// 7 ビット目から 0 ビット目への順番で、10000011 になる
// 
// 8桁 の 2進数を定義し、2進数で初期化
// bitset<8> bs("10000011");	// 7 ビット目から 0 ビット目への順番で、10000011 となる。
// string _bs; cin >> _bs; bitset<100> bs(_bs); _bs = "10000011"であれば上記と同様
// 
// 与えられる数値について、それぞれの和を算出する場合
// 下記コードでビットが立っている要素値＝和の値となる
// ex.) AGC 020 C https://atcoder.jp/contests/agc020/tasks/agc020_c
// bitset<1000> dp;
// p[0] = 1;
// for (int i = 0; i < N; ++i) {
//    dp |= (dp << A[i]);
// }

// ■絶対値
template<typename T>
static T _abs(const T x) { return  (x > 0 ? x : -x); }

// ■最大公約数
int64_t gcd(int64_t a, int64_t b) { while (b) { int64_t c = b; b = a % b; a = c; } return a; }
// ■最小公倍数
int64_t lcm(int64_t a, int64_t b) { if (!a || !b) return 0; return a * b / gcd(a, b); }

// ■多次元 std::vector 生成
template<class T>
vector<T> make_vec(size_t a) { return vector<T>(a); }
template<class T, class... Ts>
auto make_vec(size_t a, Ts... ts) { return vector<decltype(make_vec<T>(ts...))>(a, make_vec<T>(ts...)); }
// ex) auto dp = make_vec<uint64_t>(SIZE + 1, 2, 2);

// ■2次元 vector の初期化
// vector< vector<int> >  s( n, vector<int>(m, 0) );

// ■
// UINT32_MAX
// 4294967295 ≒ 4 * 1e9

// ■
// 割り算した結果との比較での丸め対処時 
// ABC 161 B
// https://atcoder.jp/contests/abc161/tasks/abc161_b
// double   border = _sum(v, 0 / (double)(4 * m);
//            ↓
// uint32_t border = (_sum(v, 0) + (4 * m) - 1) / (4 * m);

// ■
// N の数が与えられた場合の組合せ N * (N - 1) / 2


// AGC 023 A
// https://atcoder.jp/contests/agc023/tasks/agc023_a
/*
	A - Zero-Sum Ranges
	■問題文
	長さ N の整数列 A があります。
	A の 空でない 連続する 部分列であって、その総和が 0 になるものの個数を求めてください。 
	ただし、ここで数えるのは 部分列の取り出し方 であることに注意してください。 
	つまり、ある 2 つの部分列が列として同じでも、取り出した位置が異なるならば、それらは別々に数えるものとします。
*/

int main()
{
	int32_t n;
	cin >> n;

	vector<int32_t> v(n);
	vector<int64_t> s(n + 1);
	
	s[0] = 0;
	for (int32_t i = 0; i < n; i++) {
		cin >> v[i];
		s[i + 1] = v[i] + s[i];
	}

	int32_t result = 0;
	for (int32_t i = 0; i < n; i++) {
		for (int32_t j = i + 1; j <= n; j++) {
			if ((s[j] - s[i])) { continue; }
			result++;
		}
	}

	printf("%d\n", result);
	return 0;
}

// プログラムの実行: Ctrl + F5 または [デバッグ] > [デバッグなしで開始] メニュー
// プログラムのデバッグ: F5 または [デバッグ] > [デバッグの開始] メニュー

// 作業を開始するためのヒント: 
//    1. ソリューション エクスプローラー ウィンドウを使用してファイルを追加/管理します 
//   2. チーム エクスプローラー ウィンドウを使用してソース管理に接続します
//   3. 出力ウィンドウを使用して、ビルド出力とその他のメッセージを表示します
//   4. エラー一覧ウィンドウを使用してエラーを表示します
//   5. [プロジェクト] > [新しい項目の追加] と移動して新しいコード ファイルを作成するか、[プロジェクト] > [既存の項目の追加] と移動して既存のコード ファイルをプロジェクトに追加します
//   6. 後ほどこのプロジェクトを再び開く場合、[ファイル] > [開く] > [プロジェクト] と移動して .sln ファイルを選択します
