package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
)

var reader = bufio.NewReader(os.Stdin)

func main() {
	var n int
	fmt.Fscan(reader, &n)

	var s string
	fmt.Fscan(reader, &s)

	runeMap := [26][]int{}
	for i := n - 1; i >= 0; i-- {
		r := s[i] - 'a'
		runeMap[r] = append(runeMap[r], n-i-1)
	}

	pos := []int{}
	for _, r := range s {
		v := runeMap[r-'a'][0]
		runeMap[r-'a'] = runeMap[r-'a'][1:]
		pos = append(pos, v)
	}

	var swaps int64
	f := New(n)
	for i := n - 1; i >= 0; i-- {
		swaps += f.Sum(0, pos[i])
		f.Add(pos[i], 1)
	}

	fmt.Println(swaps)
}

type Fenwick struct {
	data []int
}

func New(size int) *Fenwick {
	var f Fenwick
	f.data = make([]int, size)
	return &f
}

func (f *Fenwick) Add(pos int, value int) error {
	if pos < 0 || pos >= len(f.data) {
		return errors.New("index is out of range")
	}

	for ; pos < len(f.data); pos = pos | (pos + 1) {
		f.data[pos] += value
	}

	return nil
}

func (f *Fenwick) Sum(begin, end int) int64 {
	endSum := f.prefixSum(end)
	beginSum := f.prefixSum(begin - 1)
	return endSum - beginSum
}

func (f *Fenwick) prefixSum(pos int) int64 {
	var result int64
	if pos >= len(f.data) {
		pos = len(f.data) - 1
	}

	for ; pos >= 0; pos = (pos & (pos + 1)) - 1 {
		result += int64(f.data[pos])
	}

	return result
}

/*
URL:
https://codeforces.com/contest/1430/problem/E
*/

package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func Reverse(A []rune) []rune {
	res := []rune{}

	n := len(A)
	for i := n - 1; i >= 0; i-- {
		res = append(res, A[i])
	}

	return res
}

var (
	n int
	S []rune

	U [30][]int
)

func main() {
	defer stdout.Flush()

	n = readi()
	S = readrs()

	for i := 0; i < n; i++ {
		c := S[i] - 'a'
		U[c] = append(U[c], i)
	}

	f := func(lv, rv T) T {
		return lv + rv
	}
	g := func(to T, from E) T {
		return to + T(from)
	}
	h := func(to, from E) E {
		return to + from
	}
	p := func(e E, length int) E {
		return e * E(length)
	}
	ti := T(0)
	ei := E(0)
	lst := NewLazySegmentTree(n, f, g, h, p, ti, ei)

	ans := int64(0)
	revS := Reverse(S)

	if string(S) == string(revS) {
		printf("0\n")
		return
	}

	for i := 0; i < n; i++ {
		c := revS[i] - 'a'

		idx := U[c][0]
		U[c] = U[c][1:] // 捨てる

		plus := int(lst.Query(idx, idx+1))
		j := idx + plus

		ans += int64(j - i)

		lst.Update(0, idx, E(1))
	}

	printf("%d\n", ans)
}

// Assumption: T == E
type T int // (T, f): Monoid
type E int // (E, h): Operator Monoid

type LazySegmentTree struct {
	sz   int
	data []T
	lazy []E
	f    func(lv, rv T) T        // T <> T -> T
	g    func(to T, from E) T    // T <> E -> T (assignment operator)
	h    func(to, from E) E      // E <> E -> E (assignment operator)
	p    func(e E, length int) E // E <> N -> E
	ti   T
	ei   E
}

func NewLazySegmentTree(
	n int,
	f func(lv, rv T) T, g func(to T, from E) T,
	h func(to, from E) E, p func(e E, length int) E,
	ti T, ei E,
) *LazySegmentTree {
	lst := new(LazySegmentTree)
	lst.f, lst.g, lst.h, lst.p = f, g, h, p
	lst.ti, lst.ei = ti, ei

	lst.sz = 1
	for lst.sz < n {
		lst.sz *= 2
	}

	lst.data = make([]T, 2*lst.sz-1)
	lst.lazy = make([]E, 2*lst.sz-1)
	for i := 0; i < 2*lst.sz-1; i++ {
		lst.data[i] = lst.ti
		lst.lazy[i] = lst.ei
	}

	return lst
}

func (lst *LazySegmentTree) Set(k int, x T) {
	lst.data[k+(lst.sz-1)] = x
}

func (lst *LazySegmentTree) Build() {
	for i := lst.sz - 2; i >= 0; i-- {
		lst.data[i] = lst.f(lst.data[2*i+1], lst.data[2*i+2])
	}
}

func (lst *LazySegmentTree) propagate(k, length int) {
	if lst.lazy[k] != lst.ei {
		if k < lst.sz-1 {
			lst.lazy[2*k+1] = lst.h(lst.lazy[2*k+1], lst.lazy[k])
			lst.lazy[2*k+2] = lst.h(lst.lazy[2*k+2], lst.lazy[k])
		}
		lst.data[k] = lst.g(lst.data[k], lst.p(lst.lazy[k], length))
		lst.lazy[k] = lst.ei
	}
}

func (lst *LazySegmentTree) Update(a, b int, x E) T {
	return lst.update(a, b, x, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) update(a, b int, x E, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.data[k]
	}

	if a <= l && r <= b {
		lst.lazy[k] = lst.h(lst.lazy[k], x)
		lst.propagate(k, r-l)
		return lst.data[k]
	}

	lv := lst.update(a, b, x, 2*k+1, l, (l+r)/2)
	rv := lst.update(a, b, x, 2*k+2, (l+r)/2, r)
	lst.data[k] = lst.f(lv, rv)
	return lst.data[k]
}

func (lst *LazySegmentTree) Query(a, b int) T {
	return lst.query(a, b, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) query(a, b, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.ti
	}

	if a <= l && r <= b {
		return lst.data[k]
	}

	lv := lst.query(a, b, 2*k+1, l, (l+r)/2)
	rv := lst.query(a, b, 2*k+2, (l+r)/2, r)
	return lst.f(lv, rv)
}

func (lst *LazySegmentTree) Get(k int) T {
	return lst.Query(k, k+1)
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

/*
URL:
https://codeforces.com/contest/1430/problem/E
*/

package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func Reverse(A []rune) []rune {
	res := []rune{}

	n := len(A)
	for i := n - 1; i >= 0; i-- {
		res = append(res, A[i])
	}

	return res
}

var (
	n int
	S []rune

	C [30][]int
)

func main() {
	defer stdout.Flush()

	n = readi()
	S = readrs()
	revS := Reverse(S)

	for i, rr := range S {
		r := rr - 'a'
		C[r] = append(C[r], i)
	}

	A := []int{}
	for _, rr := range revS {
		r := rr - 'a'
		A = append(A, C[r][0])
		C[r] = C[r][1:]
	}

	ans := InversionNumber(A)

	fmt.Println(ans)
}

type FenwickTree struct {
	dat     []int
	n       int
	minPow2 int
}

// n(>=1) is number of elements of original data
func NewFenwickTree(n int) *FenwickTree {
	ft := new(FenwickTree)

	ft.dat = make([]int, n+1)
	ft.n = n

	ft.minPow2 = 1
	for {
		if (ft.minPow2 << 1) > n {
			break
		}
		ft.minPow2 <<= 1
	}

	return ft
}

// Add x to i.
// i is 0-index.
func (ft *FenwickTree) Add(i int, x int) {
	ft._add(i+1, x)
}

// RangeSum calculates a range sum of [l, r).
// l, r are 0-index.
func (ft *FenwickTree) RangeSum(l, r int) int {
	res := ft._cumsum(r) - ft._cumsum(l)

	return res
}

// LowerBound returns minimum i such that bit.Sum(i) >= w.
// LowerBound returns n, if the total sum is less than w.
func (ft *FenwickTree) LowerBound(w int) int {
	if w <= 0 {
		return 0
	}

	x := 0
	for k := ft.minPow2; k > 0; k /= 2 {
		if x+k <= ft.n && ft.dat[x+k] < w {
			w -= ft.dat[x+k]
			x += k
		}
	}

	return x
}

// private: Sum of [1, i](1-based)
func (ft *FenwickTree) _cumsum(i int) int {
	s := 0

	for i > 0 {
		s += ft.dat[i]
		i -= i & (-i)
	}

	return s
}

// private: Add x to i(1-based)
func (ft *FenwickTree) _add(i, x int) {
	for i <= ft.n {
		ft.dat[i] += x
		i += i & (-i)
	}
}

// InversionNumber returns 転倒数 of slice A.
// Time complexity: O(NlogN)
func InversionNumber(A []int) (res int64) {
	_max := func(integers ...int) int {
		m := integers[0]
		for i, integer := range integers {
			if i == 0 {
				continue
			}
			if m < integer {
				m = integer
			}
		}
		return m
	}

	res = 0

	maximum := _max(A...)
	ft := NewFenwickTree(maximum + 1)

	for i := 0; i < len(A); i++ {
		res += int64(i - ft.RangeSum(0, A[i]+1))
		ft.Add(A[i], 1)
	}

	return res
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

/*
URL:
https://codeforces.com/contest/1430/problem/E
*/

package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func Reverse(A []rune) []rune {
	res := []rune{}

	n := len(A)
	for i := n - 1; i >= 0; i-- {
		res = append(res, A[i])
	}

	return res
}

var (
	n int
	S []rune

	C [30][]int
)

func main() {
	defer stdout.Flush()

	n = readi()
	S = readrs()
	revS := Reverse(S)

	for i, rr := range S {
		r := rr - 'a'
		C[r] = append(C[r], i)
	}

	A := []int{}
	for _, rr := range revS {
		r := rr - 'a'
		A = append(A, C[r][0])
		C[r] = C[r][1:]
	}

	ans := InversionNumber(A)

	fmt.Println(ans)
}

func InversionNumber(A []int) int64 {
	var res int64
	res = 0

	ft := NewFenwickTree(len(A))
	for i := 0; i < len(A); i++ {
		res += int64(i - ft.RangeSum(0, A[i]))
		ft.Add(A[i], 1)
	}

	return res
}

type FenwickTree struct {
	dat     []int
	n       int
	minPow2 int
}

// n(>=1) is number of elements of original data
func NewFenwickTree(n int) *FenwickTree {
	ft := new(FenwickTree)

	ft.dat = make([]int, n+1)
	ft.n = n

	ft.minPow2 = 1
	for {
		if (ft.minPow2 << 1) > n {
			break
		}
		ft.minPow2 <<= 1
	}

	return ft
}

// Add x to i.
// i is 0-index.
func (ft *FenwickTree) Add(i int, x int) {
	ft._add(i+1, x)
}

// RangeSum calculates a range sum of [l, r).
// l, r are 0-index.
func (ft *FenwickTree) RangeSum(l, r int) int {
	res := ft._cumsum(r) - ft._cumsum(l)

	return res
}

// LowerBound returns minimum i such that bit.Sum(i) >= w.
// LowerBound returns n, if the total sum is less than w.
func (ft *FenwickTree) LowerBound(w int) int {
	if w <= 0 {
		return 0
	}

	x := 0
	for k := ft.minPow2; k > 0; k /= 2 {
		if x+k <= ft.n && ft.dat[x+k] < w {
			w -= ft.dat[x+k]
			x += k
		}
	}

	return x
}

// private: Sum of [1, i](1-based)
func (ft *FenwickTree) _cumsum(i int) int {
	s := 0

	for i > 0 {
		s += ft.dat[i]
		i -= i & (-i)
	}

	return s
}

// private: Add x to i(1-based)
func (ft *FenwickTree) _add(i, x int) {
	for i <= ft.n {
		ft.dat[i] += x
		i += i & (-i)
	}
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

/*
URL:
https://codeforces.com/contest/1430/problem/E
*/

package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func Reverse(A []rune) []rune {
	res := []rune{}

	n := len(A)
	for i := n - 1; i >= 0; i-- {
		res = append(res, A[i])
	}

	return res
}

var (
	n int
	S []rune

	U [30][]int
)

func main() {
	defer stdout.Flush()

	n = readi()
	S = readrs()

	for i := 0; i < n; i++ {
		c := S[i] - 'a'
		U[c] = append(U[c], i)
	}

	f := func(lv, rv T) T {
		return lv + rv
	}
	g := func(to T, from E) T {
		return to + T(from)
	}
	h := func(to, from E) E {
		return to + from
	}
	p := func(e E, length int) E {
		return e * E(length)
	}
	ti := T(0)
	ei := E(0)
	lst := NewLazySegmentTree(n, f, g, h, p, ti, ei)

	// ans := 0
	ans := int64(0)
	revS := Reverse(S)

	if string(S) == string(revS) {
		printf("0\n")
		return
	}

	for i := 0; i < n; i++ {
		c := revS[i] - 'a'

		idx := U[c][0]
		U[c] = U[c][1:] // 捨てる

		// plus := ft.RangeSum(0, idx)
		plus := int(lst.Query(idx, idx+1))
		j := idx + plus

		// ans += j - i
		ans += int64(j - i)
		// debugf("%d: %d\n", i, j-i)

		// if idx-1 >= 0 {
		// ft.Add(j-1, 1)
		lst.Update(0, idx, E(1))
		// }
	}

	printf("%d\n", ans)
}

// Assumption: T == E
type T int // (T, f): Monoid
type E int // (E, h): Operator Monoid

type LazySegmentTree struct {
	sz   int
	data []T
	lazy []E
	f    func(lv, rv T) T        // T <> T -> T
	g    func(to T, from E) T    // T <> E -> T (assignment operator)
	h    func(to, from E) E      // E <> E -> E (assignment operator)
	p    func(e E, length int) E // E <> N -> E
	ti   T
	ei   E
}

func NewLazySegmentTree(
	n int,
	f func(lv, rv T) T, g func(to T, from E) T,
	h func(to, from E) E, p func(e E, length int) E,
	ti T, ei E,
) *LazySegmentTree {
	lst := new(LazySegmentTree)
	lst.f, lst.g, lst.h, lst.p = f, g, h, p
	lst.ti, lst.ei = ti, ei

	lst.sz = 1
	for lst.sz < n {
		lst.sz *= 2
	}

	lst.data = make([]T, 2*lst.sz-1)
	lst.lazy = make([]E, 2*lst.sz-1)
	for i := 0; i < 2*lst.sz-1; i++ {
		lst.data[i] = lst.ti
		lst.lazy[i] = lst.ei
	}

	return lst
}

func (lst *LazySegmentTree) Set(k int, x T) {
	lst.data[k+(lst.sz-1)] = x
}

func (lst *LazySegmentTree) Build() {
	for i := lst.sz - 2; i >= 0; i-- {
		lst.data[i] = lst.f(lst.data[2*i+1], lst.data[2*i+2])
	}
}

func (lst *LazySegmentTree) propagate(k, length int) {
	if lst.lazy[k] != lst.ei {
		if k < lst.sz-1 {
			lst.lazy[2*k+1] = lst.h(lst.lazy[2*k+1], lst.lazy[k])
			lst.lazy[2*k+2] = lst.h(lst.lazy[2*k+2], lst.lazy[k])
		}
		lst.data[k] = lst.g(lst.data[k], lst.p(lst.lazy[k], length))
		lst.lazy[k] = lst.ei
	}
}

func (lst *LazySegmentTree) Update(a, b int, x E) T {
	return lst.update(a, b, x, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) update(a, b int, x E, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.data[k]
	}

	if a <= l && r <= b {
		lst.lazy[k] = lst.h(lst.lazy[k], x)
		lst.propagate(k, r-l)
		return lst.data[k]
	}

	lv := lst.update(a, b, x, 2*k+1, l, (l+r)/2)
	rv := lst.update(a, b, x, 2*k+2, (l+r)/2, r)
	lst.data[k] = lst.f(lv, rv)
	return lst.data[k]
}

func (lst *LazySegmentTree) Query(a, b int) T {
	return lst.query(a, b, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) query(a, b, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.ti
	}

	if a <= l && r <= b {
		return lst.data[k]
	}

	lv := lst.query(a, b, 2*k+1, l, (l+r)/2)
	rv := lst.query(a, b, 2*k+2, (l+r)/2, r)
	return lst.f(lv, rv)
}

func (lst *LazySegmentTree) Get(k int) T {
	return lst.Query(k, k+1)
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

// github.com/EndlessCheng/codeforces-go
func CF1430E(_r io.Reader, out io.Writer) {
	var n int
	var s []byte
	Fscan(bufio.NewReader(_r), &n, &s)
	tree := make([]int, n+1)
	add := func(i int) {
		for ; i <= n; i += i & -i {
			tree[i]++
		}
	}
	sum := func(i int) (res int) {
		for ; i > 0; i &= i - 1 {
			res += tree[i]
		}
		return
	}
	query := func(l, r int) int { return sum(r) - sum(l-1) }

	posS := [26][]int{}
	t := make([]byte, n)
	for i, b := range s {
		b -= 'a'
		t[n-1-i] = b
		posS[b] = append(posS[b], i)
	}
	ans := int64(0)
	for i, b := range t {
		p := posS[b][0]
		posS[b] = posS[b][1:]
		ans += int64(p + query(p+1, n) - i)
		add(p + 1)
	}
	Fprint(out, ans)
}

func main() { CF1430E(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	. "fmt"
	"io"
	"os"
)

type fenwick struct {
	tree []int
}

func newFenwickTree(n int) fenwick {
	return fenwick{make([]int, n+1)}
}
func (f fenwick) add(i int, val int) {
	i++
	for ; i < len(f.tree); i += i & -i {
		f.tree[i] += val
	}
}
func (f fenwick) sum(i int) (res int) {
	i++
	for ; i > 0; i &= i - 1 {
		res += f.tree[i]
	}
	return
}
func (f fenwick) query(l, r int) (res int) { // [l,r]
	return f.sum(r) - f.sum(l-1)
}

// github.com/EndlessCheng/codeforces-go
func run(_r io.Reader, _w io.Writer) {
	in := bufio.NewReader(_r)
	out := bufio.NewWriter(_w)
	defer out.Flush()

	var n int
	var s []byte
	Fscan(in, &n, &s)

	posS := [26][]int{}
	t := make([]byte, n)
	for i, b := range s {
		b -= 'a'
		t[n-1-i] = b
		posS[b] = append(posS[b], i)
	}

	//posT := [26][]int{}
	//for i, b := range t {
	//	posT[b] = append(posT[b], i)
	//}

	f := newFenwickTree(n)
	ans := int64(0)
	for i, b := range t {
		ps := posS[b][0]
		posS[b] = posS[b][1:]

		delta := f.query(ps, n-1)
		ans += int64(ps + delta - i)

		f.add(ps, 1)
	}
	Fprintln(out, ans)
}

func main() { run(os.Stdin, os.Stdout) }

package main

import (
	"bufio"
	"fmt"
	"os"
)

var _r = bufio.NewReader(os.Stdin)
var _w = bufio.NewWriter(os.Stdout)

var n int
var s []byte

const maxn int = 2e5 + 7

var bitTree [maxn]int

func lowbit(x int) int {
	return x & (-x)
}

func modify(pos int, val int) {
	for ; pos <= n; pos += lowbit(pos) {
		bitTree[pos] += val
	}
}

func query(pos int) (res int) {
	for ; pos > 0; pos -= lowbit(pos) {
		res += bitTree[pos]
	}
	return
}

func sum(l int, r int) int {
	return query(r) - query(l-1)
}

func main() {
	_, _ = fmt.Fscan(_r, &n, &s)
	t := make([]byte, n)
	for i, i2 := range s {
		t[n-1-i] = i2
	}
	pos := [26][]int{}
	for i, i2 := range t {
		pos[i2-'a'] = append(pos[i2-'a'], i)
	}
	var p []int
	for _, i2 := range s {
		p = append(p, pos[i2-'a'][0]+1)
		pos[i2-'a'] = pos[i2-'a'][1:]
	}
	ans := int64(0)
	for _, i2 := range p {
		ans += int64(sum(i2+1, n))
		modify(i2,1)
	}
	fmt.Println(ans)
}

/*
URL:
https://codeforces.com/contest/1430/problem/E
*/

package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func Reverse(A []rune) []rune {
	res := []rune{}

	n := len(A)
	for i := n - 1; i >= 0; i-- {
		res = append(res, A[i])
	}

	return res
}

var (
	n int
	S []rune

	U [30][]int
)

func main() {
	defer stdout.Flush()

	n = readi()
	S = readrs()

	for i := 0; i < n; i++ {
		c := S[i] - 'a'
		U[c] = append(U[c], i)
	}

	f := func(lv, rv T) T {
		return lv + rv
	}
	g := func(to T, from E) T {
		return to + T(from)
	}
	h := func(to, from E) E {
		return to + from
	}
	p := func(e E, length int) E {
		return e * E(length)
	}
	ti := T(0)
	ei := E(0)
	lst := NewLazySegmentTree(n, f, g, h, p, ti, ei)

	ans := 0
	revS := Reverse(S)
	for i := 0; i < n; i++ {
		c := revS[i] - 'a'

		idx := U[c][0]
		U[c] = U[c][1:] // 捨てる

		// plus := ft.RangeSum(0, idx)
		plus := int(lst.Query(idx, idx+1))
		j := idx + plus

		ans += j - i
		// debugf("%d: %d\n", i, j-i)

		// if idx-1 >= 0 {
		// ft.Add(j-1, 1)
		lst.Update(0, idx, E(1))
		// }
	}

	printf("%d\n", ans)
}

// Assumption: T == E
type T int // (T, f): Monoid
type E int // (E, h): Operator Monoid

type LazySegmentTree struct {
	sz   int
	data []T
	lazy []E
	f    func(lv, rv T) T        // T <> T -> T
	g    func(to T, from E) T    // T <> E -> T (assignment operator)
	h    func(to, from E) E      // E <> E -> E (assignment operator)
	p    func(e E, length int) E // E <> N -> E
	ti   T
	ei   E
}

func NewLazySegmentTree(
	n int,
	f func(lv, rv T) T, g func(to T, from E) T,
	h func(to, from E) E, p func(e E, length int) E,
	ti T, ei E,
) *LazySegmentTree {
	lst := new(LazySegmentTree)
	lst.f, lst.g, lst.h, lst.p = f, g, h, p
	lst.ti, lst.ei = ti, ei

	lst.sz = 1
	for lst.sz < n {
		lst.sz *= 2
	}

	lst.data = make([]T, 2*lst.sz-1)
	lst.lazy = make([]E, 2*lst.sz-1)
	for i := 0; i < 2*lst.sz-1; i++ {
		lst.data[i] = lst.ti
		lst.lazy[i] = lst.ei
	}

	return lst
}

func (lst *LazySegmentTree) Set(k int, x T) {
	lst.data[k+(lst.sz-1)] = x
}

func (lst *LazySegmentTree) Build() {
	for i := lst.sz - 2; i >= 0; i-- {
		lst.data[i] = lst.f(lst.data[2*i+1], lst.data[2*i+2])
	}
}

func (lst *LazySegmentTree) propagate(k, length int) {
	if lst.lazy[k] != lst.ei {
		if k < lst.sz-1 {
			lst.lazy[2*k+1] = lst.h(lst.lazy[2*k+1], lst.lazy[k])
			lst.lazy[2*k+2] = lst.h(lst.lazy[2*k+2], lst.lazy[k])
		}
		lst.data[k] = lst.g(lst.data[k], lst.p(lst.lazy[k], length))
		lst.lazy[k] = lst.ei
	}
}

func (lst *LazySegmentTree) Update(a, b int, x E) T {
	return lst.update(a, b, x, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) update(a, b int, x E, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.data[k]
	}

	if a <= l && r <= b {
		lst.lazy[k] = lst.h(lst.lazy[k], x)
		lst.propagate(k, r-l)
		return lst.data[k]
	}

	lv := lst.update(a, b, x, 2*k+1, l, (l+r)/2)
	rv := lst.update(a, b, x, 2*k+2, (l+r)/2, r)
	lst.data[k] = lst.f(lv, rv)
	return lst.data[k]
}

func (lst *LazySegmentTree) Query(a, b int) T {
	return lst.query(a, b, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) query(a, b, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.ti
	}

	if a <= l && r <= b {
		return lst.data[k]
	}

	lv := lst.query(a, b, 2*k+1, l, (l+r)/2)
	rv := lst.query(a, b, 2*k+2, (l+r)/2, r)
	return lst.f(lv, rv)
}

func (lst *LazySegmentTree) Get(k int) T {
	return lst.Query(k, k+1)
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

/*
URL:
https://codeforces.com/contest/1430/problem/E
*/

package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func Reverse(A []rune) []rune {
	res := []rune{}

	n := len(A)
	for i := n - 1; i >= 0; i-- {
		res = append(res, A[i])
	}

	return res
}

var (
	n int
	S []rune

	U [30][]int
)

func main() {
	defer stdout.Flush()

	n = readi()
	S = readrs()

	for i := 0; i < n; i++ {
		c := S[i] - 'a'
		U[c] = append(U[c], i)
	}

	f := func(lv, rv T) T {
		return lv + rv
	}
	g := func(to T, from E) T {
		return to + T(from)
	}
	h := func(to, from E) E {
		return to + from
	}
	p := func(e E, length int) E {
		return e * E(length)
	}
	ti := T(0)
	ei := E(0)
	lst := NewLazySegmentTree(n, f, g, h, p, ti, ei)

	ans := 0
	revS := Reverse(S)

	if string(S) == string(revS) {
		printf("0\n")
		return
	}

	for i := 0; i < n; i++ {
		c := revS[i] - 'a'

		idx := U[c][0]
		U[c] = U[c][1:] // 捨てる

		// plus := ft.RangeSum(0, idx)
		plus := int(lst.Query(idx, idx+1))
		j := idx + plus

		ans += j - i
		// debugf("%d: %d\n", i, j-i)

		// if idx-1 >= 0 {
		// ft.Add(j-1, 1)
		lst.Update(0, idx, E(1))
		// }
	}

	printf("%d\n", ans)
}

// Assumption: T == E
type T int // (T, f): Monoid
type E int // (E, h): Operator Monoid

type LazySegmentTree struct {
	sz   int
	data []T
	lazy []E
	f    func(lv, rv T) T        // T <> T -> T
	g    func(to T, from E) T    // T <> E -> T (assignment operator)
	h    func(to, from E) E      // E <> E -> E (assignment operator)
	p    func(e E, length int) E // E <> N -> E
	ti   T
	ei   E
}

func NewLazySegmentTree(
	n int,
	f func(lv, rv T) T, g func(to T, from E) T,
	h func(to, from E) E, p func(e E, length int) E,
	ti T, ei E,
) *LazySegmentTree {
	lst := new(LazySegmentTree)
	lst.f, lst.g, lst.h, lst.p = f, g, h, p
	lst.ti, lst.ei = ti, ei

	lst.sz = 1
	for lst.sz < n {
		lst.sz *= 2
	}

	lst.data = make([]T, 2*lst.sz-1)
	lst.lazy = make([]E, 2*lst.sz-1)
	for i := 0; i < 2*lst.sz-1; i++ {
		lst.data[i] = lst.ti
		lst.lazy[i] = lst.ei
	}

	return lst
}

func (lst *LazySegmentTree) Set(k int, x T) {
	lst.data[k+(lst.sz-1)] = x
}

func (lst *LazySegmentTree) Build() {
	for i := lst.sz - 2; i >= 0; i-- {
		lst.data[i] = lst.f(lst.data[2*i+1], lst.data[2*i+2])
	}
}

func (lst *LazySegmentTree) propagate(k, length int) {
	if lst.lazy[k] != lst.ei {
		if k < lst.sz-1 {
			lst.lazy[2*k+1] = lst.h(lst.lazy[2*k+1], lst.lazy[k])
			lst.lazy[2*k+2] = lst.h(lst.lazy[2*k+2], lst.lazy[k])
		}
		lst.data[k] = lst.g(lst.data[k], lst.p(lst.lazy[k], length))
		lst.lazy[k] = lst.ei
	}
}

func (lst *LazySegmentTree) Update(a, b int, x E) T {
	return lst.update(a, b, x, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) update(a, b int, x E, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.data[k]
	}

	if a <= l && r <= b {
		lst.lazy[k] = lst.h(lst.lazy[k], x)
		lst.propagate(k, r-l)
		return lst.data[k]
	}

	lv := lst.update(a, b, x, 2*k+1, l, (l+r)/2)
	rv := lst.update(a, b, x, 2*k+2, (l+r)/2, r)
	lst.data[k] = lst.f(lv, rv)
	return lst.data[k]
}

func (lst *LazySegmentTree) Query(a, b int) T {
	return lst.query(a, b, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) query(a, b, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.ti
	}

	if a <= l && r <= b {
		return lst.data[k]
	}

	lv := lst.query(a, b, 2*k+1, l, (l+r)/2)
	rv := lst.query(a, b, 2*k+2, (l+r)/2, r)
	return lst.f(lv, rv)
}

func (lst *LazySegmentTree) Get(k int) T {
	return lst.Query(k, k+1)
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

/*
URL:
https://codeforces.com/contest/1430/problem/E
*/

package main

import (
	"bufio"
	"fmt"
	"io"
	"math"
	"os"
	"strconv"
)

func Reverse(A []rune) []rune {
	res := []rune{}

	n := len(A)
	for i := n - 1; i >= 0; i-- {
		res = append(res, A[i])
	}

	return res
}

var (
	n int
	S []rune

	U [30][]int
)

func main() {
	defer stdout.Flush()

	n = readi()
	S = readrs()

	for i := 0; i < n; i++ {
		c := S[i] - 'a'
		U[c] = append(U[c], i)
	}

	f := func(lv, rv T) T {
		return lv + rv
	}
	g := func(to T, from E) T {
		return to + T(from)
	}
	h := func(to, from E) E {
		return to + from
	}
	p := func(e E, length int) E {
		return e * E(length)
	}
	ti := T(0)
	ei := E(0)
	lst := NewLazySegmentTree(n+100, f, g, h, p, ti, ei)

	ans := 0
	revS := Reverse(S)
	for i := 0; i < n; i++ {
		c := revS[i] - 'a'

		idx := U[c][0]
		U[c] = U[c][1:] // 捨てる

		// plus := ft.RangeSum(0, idx)
		plus := int(lst.Query(idx, idx+1))
		j := idx + plus

		ans += j - i
		// debugf("%d: %d\n", i, j-i)

		// if idx-1 >= 0 {
		// ft.Add(j-1, 1)
		lst.Update(0, idx, E(1))
		// }
	}

	printf("%d\n", ans)
}

// Assumption: T == E
type T int // (T, f): Monoid
type E int // (E, h): Operator Monoid

type LazySegmentTree struct {
	sz   int
	data []T
	lazy []E
	f    func(lv, rv T) T        // T <> T -> T
	g    func(to T, from E) T    // T <> E -> T (assignment operator)
	h    func(to, from E) E      // E <> E -> E (assignment operator)
	p    func(e E, length int) E // E <> N -> E
	ti   T
	ei   E
}

func NewLazySegmentTree(
	n int,
	f func(lv, rv T) T, g func(to T, from E) T,
	h func(to, from E) E, p func(e E, length int) E,
	ti T, ei E,
) *LazySegmentTree {
	lst := new(LazySegmentTree)
	lst.f, lst.g, lst.h, lst.p = f, g, h, p
	lst.ti, lst.ei = ti, ei

	lst.sz = 1
	for lst.sz < n {
		lst.sz *= 2
	}

	lst.data = make([]T, 2*lst.sz-1)
	lst.lazy = make([]E, 2*lst.sz-1)
	for i := 0; i < 2*lst.sz-1; i++ {
		lst.data[i] = lst.ti
		lst.lazy[i] = lst.ei
	}

	return lst
}

func (lst *LazySegmentTree) Set(k int, x T) {
	lst.data[k+(lst.sz-1)] = x
}

func (lst *LazySegmentTree) Build() {
	for i := lst.sz - 2; i >= 0; i-- {
		lst.data[i] = lst.f(lst.data[2*i+1], lst.data[2*i+2])
	}
}

func (lst *LazySegmentTree) propagate(k, length int) {
	if lst.lazy[k] != lst.ei {
		if k < lst.sz-1 {
			lst.lazy[2*k+1] = lst.h(lst.lazy[2*k+1], lst.lazy[k])
			lst.lazy[2*k+2] = lst.h(lst.lazy[2*k+2], lst.lazy[k])
		}
		lst.data[k] = lst.g(lst.data[k], lst.p(lst.lazy[k], length))
		lst.lazy[k] = lst.ei
	}
}

func (lst *LazySegmentTree) Update(a, b int, x E) T {
	return lst.update(a, b, x, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) update(a, b int, x E, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.data[k]
	}

	if a <= l && r <= b {
		lst.lazy[k] = lst.h(lst.lazy[k], x)
		lst.propagate(k, r-l)
		return lst.data[k]
	}

	lv := lst.update(a, b, x, 2*k+1, l, (l+r)/2)
	rv := lst.update(a, b, x, 2*k+2, (l+r)/2, r)
	lst.data[k] = lst.f(lv, rv)
	return lst.data[k]
}

func (lst *LazySegmentTree) Query(a, b int) T {
	return lst.query(a, b, 0, 0, lst.sz)
}

func (lst *LazySegmentTree) query(a, b, k, l, r int) T {
	lst.propagate(k, r-l)

	if r <= a || b <= l {
		return lst.ti
	}

	if a <= l && r <= b {
		return lst.data[k]
	}

	lv := lst.query(a, b, 2*k+1, l, (l+r)/2)
	rv := lst.query(a, b, 2*k+2, (l+r)/2, r)
	return lst.f(lv, rv)
}

func (lst *LazySegmentTree) Get(k int) T {
	return lst.Query(k, k+1)
}

/*******************************************************************/

/********** common constants **********/

const (
	MOD = 1000000000 + 7
	// MOD          = 998244353
	ALPH_N  = 26
	INF_I64 = math.MaxInt64
	INF_B60 = 1 << 60
	INF_I32 = math.MaxInt32
	INF_B30 = 1 << 30
	NIL     = -1
	EPS     = 1e-10
)

/********** bufio setting **********/

func init() {
	// bufio.ScanWords <---> bufio.ScanLines
	reads = newReadString(os.Stdin, bufio.ScanWords)
	stdout = bufio.NewWriter(os.Stdout)
}

// mod can calculate a right residual whether value is positive or negative.
func mod(val, m int) int {
	res := val % m
	if res < 0 {
		res += m
	}
	return res
}

// min returns the min integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func min(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m > integer {
			m = integer
		}
	}
	return m
}

// max returns the max integer among input set.
// This function needs at least 1 argument (no argument causes panic).
func max(integers ...int) int {
	m := integers[0]
	for i, integer := range integers {
		if i == 0 {
			continue
		}
		if m < integer {
			m = integer
		}
	}
	return m
}

// chmin accepts a pointer of integer and a target value.
// If target value is SMALLER than the first argument,
//	then the first argument will be updated by the second argument.
func chmin(updatedValue *int, target int) bool {
	if *updatedValue > target {
		*updatedValue = target
		return true
	}
	return false
}

// chmax accepts a pointer of integer and a target value.
// If target value is LARGER than the first argument,
//	then the first argument will be updated by the second argument.
func chmax(updatedValue *int, target int) bool {
	if *updatedValue < target {
		*updatedValue = target
		return true
	}
	return false
}

// sum returns multiple integers sum.
func sum(integers ...int) int {
	var s int
	s = 0

	for _, i := range integers {
		s += i
	}

	return s
}

/********** FAU standard libraries **********/

//fmt.Sprintf("%b\n", 255) 	// binary expression

/********** I/O usage **********/

//str := reads()
//i := readi()
//X := readis(n)
//S := readrs()
//a := readf()
//A := readfs(n)

//str := ZeroPaddingRuneSlice(num, 32)
//str := PrintIntsLine(X...)

/*********** Input ***********/

var (
	// reads returns a WORD string.
	reads  func() string
	stdout *bufio.Writer
)

func newReadString(ior io.Reader, sf bufio.SplitFunc) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+9)) // for Codeforces
	r.Split(sf)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

// readi returns an integer.
func readi() int {
	return int(_readInt64())
}
func readi2() (int, int) {
	return int(_readInt64()), int(_readInt64())
}
func readi3() (int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64())
}
func readi4() (int, int, int, int) {
	return int(_readInt64()), int(_readInt64()), int(_readInt64()), int(_readInt64())
}

// readll returns as integer as int64.
func readll() int64 {
	return _readInt64()
}
func readll2() (int64, int64) {
	return _readInt64(), _readInt64()
}
func readll3() (int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64()
}
func readll4() (int64, int64, int64, int64) {
	return _readInt64(), _readInt64(), _readInt64(), _readInt64()
}

func _readInt64() int64 {
	i, err := strconv.ParseInt(reads(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

// readis returns an integer slice that has n integers.
func readis(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readi()
	}
	return b
}

// readlls returns as int64 slice that has n integers.
func readlls(n int) []int64 {
	b := make([]int64, n)
	for i := 0; i < n; i++ {
		b[i] = readll()
	}
	return b
}

// readf returns an float64.
func readf() float64 {
	return float64(_readFloat64())
}

func _readFloat64() float64 {
	f, err := strconv.ParseFloat(reads(), 64)
	if err != nil {
		panic(err.Error())
	}
	return f
}

// ReadFloatSlice returns an float64 slice that has n float64.
func readfs(n int) []float64 {
	b := make([]float64, n)
	for i := 0; i < n; i++ {
		b[i] = readf()
	}
	return b
}

// readrs returns a rune slice.
func readrs() []rune {
	return []rune(reads())
}

/*********** Output ***********/

// PrintIntsLine returns integers string delimited by a space.
func PrintIntsLine(A ...int) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.Itoa(A[i])
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// PrintIntsLine returns integers string delimited by a space.
func PrintInts64Line(A ...int64) string {
	res := []rune{}

	for i := 0; i < len(A); i++ {
		str := strconv.FormatInt(A[i], 10) // 64bit int version
		res = append(res, []rune(str)...)

		if i != len(A)-1 {
			res = append(res, ' ')
		}
	}

	return string(res)
}

// Printf is function for output strings to buffered os.Stdout.
// You may have to call stdout.Flush() finally.
func printf(format string, a ...interface{}) {
	fmt.Fprintf(stdout, format, a...)
}

/*********** Debugging ***********/

// debugf is wrapper of fmt.Fprintf(os.Stderr, format, a...)
func debugf(format string, a ...interface{}) {
	fmt.Fprintf(os.Stderr, format, a...)
}

// ZeroPaddingRuneSlice returns binary expressions of integer n with zero padding.
// For debugging use.
func ZeroPaddingRuneSlice(n, digitsNum int) []rune {
	sn := fmt.Sprintf("%b", n)

	residualLength := digitsNum - len(sn)
	if residualLength <= 0 {
		return []rune(sn)
	}

	zeros := make([]rune, residualLength)
	for i := 0; i < len(zeros); i++ {
		zeros[i] = '0'
	}

	res := []rune{}
	res = append(res, zeros...)
	res = append(res, []rune(sn)...)

	return res
}

package main

import (
	"bufio"
	"errors"
	"fmt"
	"os"
)

var reader = bufio.NewReader(os.Stdin)

func main() {
	var n int
	fmt.Fscan(reader, &n)

	var s string
	fmt.Fscan(reader, &s)

	runeMap := [26][]int{}
	for i := n - 1; i >= 0; i-- {
		r := s[i] - 'a'
		runeMap[r] = append(runeMap[r], n-i-1)
	}

	pos := []int{}
	for _, r := range s {
		v := runeMap[r-'a'][0]
		runeMap[r-'a'] = runeMap[r-'a'][1:]
		pos = append(pos, v)
	}

	swaps := 0
	f := New(n)
	for i := n - 1; i >= 0; i-- {
		swaps += f.Sum(0, pos[i])
		f.Add(pos[i], 1)
	}

	fmt.Println(swaps)
}

type Fenwick struct {
	data []int
}

func New(size int) *Fenwick {
	var f Fenwick
	f.data = make([]int, size)
	return &f
}

func (f *Fenwick) Add(pos int, value int) error {
	if pos < 0 || pos >= len(f.data) {
		return errors.New("index is out of range")
	}

	for ; pos < len(f.data); pos = pos | (pos + 1) {
		f.data[pos] += value
	}

	return nil
}

func (f *Fenwick) Sum(begin, end int) int {
	endSum := f.prefixSum(end)
	beginSum := f.prefixSum(begin - 1)
	return endSum - beginSum
}

func (f *Fenwick) prefixSum(pos int) int {
	var result int
	if pos >= len(f.data) {
		pos = len(f.data) - 1
	}

	for ; pos >= 0; pos = (pos & (pos + 1)) - 1 {
		result += f.data[pos]
	}

	return result
}


package main

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

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool  // True if the vertex is visited during DFS
	sccID   []int   // Topological order of the vertex v
	sccSize []int   // The size of SCC indexed by sccID
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		sccID:   make([]int, size),
		sccSize: make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.sccID[v] = k
	g.sccSize[k]++
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.rdfs(g.R[v][i], k)
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

func max(x, y int) int {
	if y > x {
		return y
	}
	return x
}

type unionFind struct{ id, sz []int }

func newUnionFind(size int) *unionFind {
	uf := &unionFind{id: make([]int, size), sz: make([]int, size)}
	for i := 0; i < size; i++ {
		uf.id[i], uf.sz[i] = i, 1
	}
	return uf
}

func (uf *unionFind) root(x int) int {
	if uf.id[x] != x {
		uf.id[x] = uf.root(uf.id[x])
	}
	return uf.id[x]
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func (g *graph) dfs2(v int) (z int) {
	g.visited[v] = true
	z = g.sccSize[g.sccID[v]]
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			z = max(z, g.dfs2(g.E[v][i]))
		}
	}
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			z = max(z, g.dfs2(g.R[v][i]))
		}
	}
	return
}

func main() {
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	g.scc()
	for i := 0; i < n; i++ {
		uf.root(i)
	}
	sccSize := make([]int, n)
	for i := 0; i < n; i++ {
		sccSize[uf.id[i]] = max(sccSize[uf.id[i]], g.sccSize[g.sccID[i]])
	}
	res := n
	for i := 0; i < n; i++ {
		if sccSize[i] == 1 {
			res--
		}
	}
	fmt.Println(res)
}

package main

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

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool  // True if the vertex is visited during DFS
	sccID   []int   // Topological order of the vertex v
	sccSize []int   // The size of SCC indexed by sccID
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		sccID:   make([]int, size),
		sccSize: make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.sccID[v] = k
	g.sccSize[k]++
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.rdfs(g.R[v][i], k)
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

func max(x, y int) int {
	if y > x {
		return y
	}
	return x
}

func (g *graph) dfs2(v int) (z int) {
	g.visited[v] = true
	z = g.sccSize[g.sccID[v]]
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			z = max(z, g.dfs2(g.E[v][i]))
		}
	}
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			z = max(z, g.dfs2(g.R[v][i]))
		}
	}
	return
}

func main() {
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
	}
	g.scc()
	g.visited = make([]bool, g.V)
	res := n
	for i := 0; i < n; i++ {
		if !g.visited[i] {
			if g.dfs2(i) < 2 {
				res--
			}
		}
	}
	fmt.Println(res)
}

package main

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

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool  // True if the vertex is visited during DFS
	sccID   []int   // Topological order of the vertex v
	sccSize []int   // The size of SCC indexed by sccID
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		sccID:   make([]int, size),
		sccSize: make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.sccID[v] = k
	g.sccSize[k]++
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.rdfs(g.R[v][i], k)
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

func max(x, y int) int {
	if y > x {
		return y
	}
	return x
}

type unionFind struct {
	id []int
	sz []int
}

func newUnionFind(size int) *unionFind {
	uf := &unionFind{
		id: make([]int, size),
		sz: make([]int, size),
	}
	for i := 0; i < size; i++ {
		uf.id[i] = i
		uf.sz[i] = 1
	}
	return uf
}

func (uf *unionFind) root(x int) int {
	if uf.id[x] == x {
		return x
	}
	uf.id[x] = uf.root(uf.id[x])
	return uf.id[x]
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func (g *graph) dfs2(v int) (z int) {
	g.visited[v] = true
	z = g.sccSize[g.sccID[v]]
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			z = max(z, g.dfs2(g.E[v][i]))
		}
	}
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			z = max(z, g.dfs2(g.R[v][i]))
		}
	}
	return
}

func main() {
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	g.scc()
	for i := 0; i < n; i++ {
		uf.root(i)
	}
	sccSize := make([]int, n)
	for i := 0; i < n; i++ {
		sccSize[uf.id[i]] = max(sccSize[uf.id[i]], g.sccSize[g.sccID[i]])
	}
	res := n
	for i := 0; i < n; i++ {
		if sccSize[i] == 1 {
			res--
		}
	}
	fmt.Println(res)
}

package main

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

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool  // True if the vertex is visited during DFS
	sccID   []int   // Topological order of the vertex v
	sccSize []int   // The size of SCC indexed by sccID
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		sccID:   make([]int, size),
		sccSize: make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.sccID[v] = k
	g.sccSize[k]++
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.rdfs(g.R[v][i], k)
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

func max(x, y int) int {
	if y > x {
		return y
	}
	return x
}

type unionFind struct {
	id []int
	sz []int
}

func newUnionFind(size int) *unionFind {
	uf := &unionFind{
		id: make([]int, size),
		sz: make([]int, size),
	}
	for i := 0; i < size; i++ {
		uf.id[i] = i
		uf.sz[i] = 1
	}
	return uf
}

func (uf *unionFind) root(i int) int {
	for i != uf.id[i] {
		uf.id[i] = uf.id[uf.id[i]]
		i = uf.id[i]
	}
	return i
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func (g *graph) dfs2(v int) (z int) {
	g.visited[v] = true
	z = g.sccSize[g.sccID[v]]
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			z = max(z, g.dfs2(g.E[v][i]))
		}
	}
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			z = max(z, g.dfs2(g.R[v][i]))
		}
	}
	return
}

func main() {
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	g.scc()
	for i := 1; i < n; i++ {
		uf.find(0, i)
	}
	sccSize := make([]int, n)
	for i := 0; i < n; i++ {
		sccSize[uf.id[i]] = max(sccSize[uf.id[i]], g.sccSize[g.sccID[i]])
	}
	res := n
	for i := 0; i < n; i++ {
		if sccSize[i] == 1 {
			res--
		}
	}
	fmt.Println(res)
}

package main

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

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool
	top     []int // Topological order
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		top:     make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.top[v] = k
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.dfs(g.R[v][i])
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type unionFind struct {
	id []int
	sz []int
}

func newUnionFind(size int) *unionFind {
	uf := &unionFind{
		id: make([]int, size),
		sz: make([]int, size),
	}
	for i := 0; i < size; i++ {
		uf.id[i] = i
		uf.sz[i] = 1
	}
	return uf
}

func (uf *unionFind) root(i int) int {
	for i != uf.id[i] {
		uf.id[i] = uf.id[uf.id[i]]
		i = uf.id[i]
	}
	return i
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func main() {
	n, m := nextInt(), nextInt()
	res := n
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	cc := make(map[int][]int)
	for i := 0; i < n; i++ {
		cc[uf.id[i]] = append(cc[uf.id[i]], i)
	}
	res -= len(cc)
	for _, vs := range cc {
		sg := newGraph(g.V)
		for _, v := range vs {
			sg.E[v] = g.E[v]
			sg.R[v] = g.R[v]
		}
		if sg.V > sg.scc() {
			res++
		}
	}
	fmt.Println(res)
}

package main

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

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool
	top     []int // Topological order
	sccSize []int
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		top:     make([]int, size),
		sccSize: make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.top[v] = k
	g.sccSize[k]++
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.rdfs(g.R[v][i], k)
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type unionFind struct {
	id []int
	sz []int
}

func newUnionFind(size int) *unionFind {
	uf := &unionFind{
		id: make([]int, size),
		sz: make([]int, size),
	}
	for i := 0; i < size; i++ {
		uf.id[i] = i
		uf.sz[i] = 1
	}
	return uf
}

func (uf *unionFind) root(i int) int {
	for i != uf.id[i] {
		uf.id[i] = uf.id[uf.id[i]]
		i = uf.id[i]
	}
	return i
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func main() {
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	g.scc()
	ccs, looped := make(map[int]bool), make(map[int]bool)
	for i := 0; i < n; i++ {
		ccs[uf.id[i]] = true
		if g.sccSize[g.top[i]] > 1 {
			looped[uf.id[i]] = true
		}
	}
	fmt.Println(n - len(ccs) + len(looped))
}

package main

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

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool  // True if the vertex is visited during DFS
	topID   []int   // Topological order
	sccSize []int   // The size of SCC indexed by topID
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		topID:   make([]int, size),
		sccSize: make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.topID[v] = k
	g.sccSize[k]++
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.rdfs(g.R[v][i], k)
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type unionFind struct {
	id []int
	sz []int
}

func newUnionFind(size int) *unionFind {
	uf := &unionFind{
		id: make([]int, size),
		sz: make([]int, size),
	}
	for i := 0; i < size; i++ {
		uf.id[i] = i
		uf.sz[i] = 1
	}
	return uf
}

func (uf *unionFind) root(i int) int {
	for i != uf.id[i] {
		uf.id[i] = uf.id[uf.id[i]]
		i = uf.id[i]
	}
	return i
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func max(x, y int) int {
	if y > x {
		return y
	}
	return x
}

func main() {
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	g.scc()
	maxSccSize := make(map[int]int)
	for i := 0; i < n; i++ {
		maxSccSize[uf.id[i]] = max(maxSccSize[uf.id[i]], g.sccSize[g.topID[i]])
	}
	res := n
	for _, x := range maxSccSize {
		if x < 2 {
			res--
		}
	}
	fmt.Println(res)
}

package main

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

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool
	top     []int // Topological order
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		top:     make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.top[v] = k
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.dfs(g.R[v][i])
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type unionFind struct {
	id []int
	sz []int
}

func newUnionFind(size int) *unionFind {
	uf := &unionFind{
		id: make([]int, size),
		sz: make([]int, size),
	}
	for i := 0; i < size; i++ {
		uf.id[i] = i
		uf.sz[i] = 1
	}
	return uf
}

func (uf *unionFind) root(i int) int {
	for i != uf.id[i] {
		uf.id[i] = uf.id[uf.id[i]]
		i = uf.id[i]
	}
	return i
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func main() {
	var res int
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	cc := make(map[int][]int)
	for i := 0; i < n; i++ {
		cc[uf.id[i]] = append(cc[uf.id[i]], i)
	}
	for _, vs := range cc {
		sg := newGraph(n)
		for _, v := range vs {
			sg.E[v] = g.E[v]
			sg.R[v] = g.R[v]
		}
		if sg.V > sg.scc() {
			res += len(vs)
		} else {
			res += len(vs) - 1
		}
	}
	fmt.Println(res)
}

package main

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

var sc = bufio.NewScanner(os.Stdin)

func next() string {
	sc.Split(bufio.ScanWords)
	if !sc.Scan() {
		panic("could not scan a word from the reader")
	}
	return sc.Text()
}

func nextInt() int {
	i, e := strconv.Atoi(next())
	if e != nil {
		panic(e)
	}
	return i
}

func nextLong() int64 {
	i, e := strconv.ParseInt(next(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func nextLine() string {
	sc.Split(bufio.ScanLines)
	if !sc.Scan() {
		panic("could not scan a line from the reader")
	}
	return sc.Text()
}

type graph struct {
	V       int     // The number of vetices
	E       [][]int // Adjacency list expression of the graph
	R       [][]int // Reversed E
	vs      []int   // Post order
	visited []bool  // True if the vertex is visited during DFS
	sccID   []int   // Topological order of the vertex v
	sccSize []int   // The size of SCC indexed by sccID
}

func newGraph(size int) *graph {
	g := &graph{
		V:       size,
		E:       make([][]int, size),
		R:       make([][]int, size),
		vs:      make([]int, 0, size),
		visited: make([]bool, size),
		sccID:   make([]int, size),
		sccSize: make([]int, size),
	}
	return g
}

func (g *graph) addEdge(from, to int) {
	g.E[from] = append(g.E[from], to)
	g.R[to] = append(g.R[to], from)
}

func (g *graph) dfs(v int) {
	g.visited[v] = true
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			g.dfs(g.E[v][i])
		}
	}
	g.vs = append(g.vs, v)
}

func (g *graph) rdfs(v, k int) {
	g.visited[v] = true
	g.sccID[v] = k
	g.sccSize[k]++
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			g.rdfs(g.R[v][i], k)
		}
	}
}

func (g *graph) scc() (k int) {
	g.visited = make([]bool, g.V)
	g.vs = g.vs[:0]
	for i := 0; i < g.V; i++ {
		if !g.visited[i] {
			g.dfs(i)
		}
	}
	g.visited = make([]bool, g.V)
	for i := len(g.vs) - 1; i >= 0; i-- {
		if !g.visited[g.vs[i]] {
			g.rdfs(g.vs[i], k)
			k++
		}
	}
	return k
}

func max(x, y int) int {
	if y > x {
		return y
	}
	return x
}

type unionFind struct {
	id []int
	sz []int
}

func newUnionFind(size int) *unionFind {
	uf := &unionFind{
		id: make([]int, size),
		sz: make([]int, size),
	}
	for i := 0; i < size; i++ {
		uf.id[i] = i
		uf.sz[i] = 1
	}
	return uf
}

func (uf *unionFind) root(x int) int {
	if uf.id[x] == x {
		return x
	}
	uf.id[x] = uf.root(uf.id[x])
	return uf.id[x]
}

func (uf *unionFind) find(p, q int) bool {
	return uf.root(p) == uf.root(q)
}

func (uf *unionFind) union(p, q int) {
	i, j := uf.root(p), uf.root(q)
	if uf.sz[i] < uf.sz[j] {
		uf.id[i] = j
		uf.sz[j] += uf.sz[i]
	} else {
		uf.id[j] = i
		uf.sz[i] += uf.sz[j]
	}
}

func (g *graph) dfs2(v int) (z int) {
	g.visited[v] = true
	z = g.sccSize[g.sccID[v]]
	for i, n := 0, len(g.E[v]); i < n; i++ {
		if !g.visited[g.E[v][i]] {
			z = max(z, g.dfs2(g.E[v][i]))
		}
	}
	for i, n := 0, len(g.R[v]); i < n; i++ {
		if !g.visited[g.R[v][i]] {
			z = max(z, g.dfs2(g.R[v][i]))
		}
	}
	return
}

func main() {
	n, m := nextInt(), nextInt()
	g := newGraph(n)
	uf := newUnionFind(n)
	for i := 0; i < m; i++ {
		a, b := nextInt()-1, nextInt()-1
		g.addEdge(a, b)
		uf.union(a, b)
	}
	g.scc()
	for i := 0; i < n; i++ {
		uf.root(i)
	}
	fmt.Println(uf.id)
	sccSize := make([]int, n)
	for i := 0; i < n; i++ {
		sccSize[uf.id[i]] = max(sccSize[uf.id[i]], g.sccSize[g.sccID[i]])
	}
	res := n
	for i := 0; i < n; i++ {
		if sccSize[i] == 1 {
			res--
		}
	}
	fmt.Println(res)
}