using namespace std;

#include<bits/stdc++.h>

typedef long long ll;
typedef pair<int, int> ii;
typedef pair<ll, ll> pll;
typedef vector<ii> vii;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vll;
typedef vector<vll> vvll;

#define getBit(x,i) (x&(1<<i))
#define setBit(x,i) (x|(1<<i))
#define mem(A,N) memset(A,N,sizeof(A))
#define pb push_back
#define pf push_front
#define ppb pop_back
#define ppf pop_front
#define mp make_pair
#define rep(i, x, y)  for(int i = x; i < y; ++i)
#define Rep(i, x, y)  for(int i = x; i <= y; ++i)
#define srep(i, x, y) for(int i = x; i > y; --i)
#define sRep(i, x, y) for(int i = x; i >= y; --i)
#define All(v) v.begin(),v.end()
#define sortA(a) sort(a, a+n)
#define sortArr(a, i, n) sort(a+i, a+n)
#define SortArr(a, i, n) sort(a+i, a+n+1)
#define Sort(x) sort(x.begin(), x.end())
#define f1(i,n) for (int i=1; i<=n; i++)
#define f0(i,n) for (int i=0; i<n; i++)
#define sz(x) ((int)(x).size())
#define len(x) ((int)(x).length())
#define fi first
#define se second
#define concatenate(a, b) std::copy(b.begin(), b.end(), std::back_inserter(a));
#define fcout(x) cout << fixed << setprecision(x)
#define ifcout(x, a, b) if(x) cout << a << '\n'; else cout << b << '\n'
// #define concatenate(a, b) a.insert(b.end(), b.begin(), b.end());
// std::move(b.begin(), b.end(), std::back_inserter(a)); "Undefined behaviour if a actually is b (which is OK if you know that can never happen - but worth being aware of in general purpose code)"
#define makeUnique(v) v.erase(unique(v.begin(), v.end()), v.end())
#define inRange(x, a, b) (a <= x && x < b)

#define linf 0x7FFFFFFFFFFFFFFF
#define inf 0x7FFFFFFF
#define mod 1000000007
#define eps 1e-9
#define Pi 3.14159265358979323846

//debug
#define dump(x)  cerr << #x << " = " << (x) << endl;
#define write(x) cerr << #x << " = " << (x) << ", ";
#define writeI0 cerr << "i = " << 0 << ", ";
#define dumpI0 cerr << "i = " << 0 << endl;
#define printSet(s) for(auto it = s.begin(); it!=s.end(); it++) (it==s.begin())? cout << *it : cout << ' ' << *it; cout << endl;
#define printMap(m) for(auto it = m.begin(); it!=m.end(); it++) (it==m.begin())? cout << '(' << it->first << ", " << it->second << ')' : cout << " (" << it->first << ", " << it->second << ')'; cout << endl;
#define printPairSet(s) for(auto it = s.begin(); it!=s.end(); it++) (it==s.begin())? cout << '(' << it->first << ", " << it->second << ')' : cout << " (" << it->first << ", " << it->second << ')'; cout << endl;
#define printVector(x) for(auto it = x.begin(); it!=x.end(); it++) (it==x.begin())? cout << *it : cout << ' ' << *it; cout << endl;
#define printArray(a,x,y) for(auto it = a+x; it != a+y; it++) (it==a+x)? cout << *it : cout << ' ' << *it; cout << endl;
#define PrintArray(a,x,y) for(auto it = a+x; it != a+y+1; it++) (it==a+x)? cout << *it : cout << ' ' << *it; cout << endl;

// ***************** End Of Template ********************

//int min;
//int a[200010];
//bool v[200010];
//set<int> s;

int arr[524290];
int a[524290];
int lazy[524290];
int tree[524290];

void updateRangeUtil(int si, int ss, int se, int us,
					 int ue, int diff)
{
	// If lazy value is non-zero for current node of segment
	// tree, then there are some pending updates. So we need
	// to make sure that the pending updates are done before
	// making new updates. Because this value may be used by
	// parent after recursive calls (See last line of this
	// function)
	if (lazy[si] != 0)
	{
		// Make pending updates using value stored in lazy
		// nodes
		tree[si] += (se-ss+1)*lazy[si];
		
		// checking if it is not leaf node because if
		// it is leaf node then we cannot go further
		if (ss != se)
		{
			// We can postpone updating children we don't
			// need their new values now.
			// Since we are not yet updating children of si,
			// we need to set lazy flags for the children
			lazy[si*2 + 1]   += lazy[si];
			lazy[si*2 + 2]   += lazy[si];
		}
		
		// Set the lazy value for current node as 0 as it
		// has been updated
		lazy[si] = 0;
	}
	
	// out of range
	if (ss>se || ss>ue || se<us)
		return ;
	
	// Current segment is fully in range
	if (ss>=us && se<=ue)
	{
		// Add the difference to current node
		tree[si] += (se-ss+1)*diff;
		
		// same logic for checking leaf node or not
		if (ss != se)
		{
			// This is where we store values in lazy nodes,
			// rather than updating the segment tree itelf
			// Since we don't need these updated values now
			// we postpone updates by storing values in lazy[]
			lazy[si*2 + 1]   += diff;
			lazy[si*2 + 2]   += diff;
		}
		return;
	}
	
	// If not completely in rang, but overlaps, recur for
	// children,
	int mid = (ss+se)/2;
	updateRangeUtil(si*2+1, ss, mid, us, ue, diff);
	updateRangeUtil(si*2+2, mid+1, se, us, ue, diff);
	
	// And use the result of children calls to update this
	// node
	tree[si] = tree[si*2+1] + tree[si*2+2];
}

// Function to update a range of values in segment
// tree
/*  us and eu -> starting and ending indexes of update query
    ue  -> ending index of update query
    diff -> which we need to add in the range us to ue */
void updateRange(int n, int us, int ue, int diff)
{
	updateRangeUtil(0, 0, n-1, us, ue, diff);
}


/*  A recursive function to get the sum of values in given
    range of the array. The following are parameters for
    this function.
    si --> Index of current node in the segment tree.
           Initially 0 is passed as root is always at'
           index 0
    ss & se  --> Starting and ending indexes of the
                 segment represented by current node,
                 i.e., tree[si]
    qs & qe  --> Starting and ending indexes of query
                 range */
int getSumUtil(int ss, int se, int qs, int qe, int si)
{
	// If lazy flag is set for current node of segment tree,
	// then there are some pending updates. So we need to
	// make sure that the pending updates are done before
	// processing the sub sum query
	if (lazy[si] != 0)
	{
		// Make pending updates to this node. Note that this
		// node represents sum of elements in arr[ss..se] and
		// all these elements must be increased by lazy[si]
		tree[si] += (se-ss+1)*lazy[si];
		
		// checking if it is not leaf node because if
		// it is leaf node then we cannot go further
		if (ss != se)
		{
			// Since we are not yet updating children os si,
			// we need to set lazy values for the children
			lazy[si*2+1] += lazy[si];
			lazy[si*2+2] += lazy[si];
		}
		
		// unset the lazy value for current node as it has
		// been updated
		lazy[si] = 0;
	}
	
	// Out of range
	if (ss>se || ss>qe || se<qs)
		return 0;
	
	// At this point we are sure that pending lazy updates
	// are done for current node. So we can return value
	// (same as it was for query in our previous post)
	
	// If this segment lies in range
	if (ss>=qs && se<=qe)
		return tree[si];
	
	// If a part of this segment overlaps with the given
	// range
	int mid = (ss + se)/2;
	return getSumUtil(ss, mid, qs, qe, 2*si+1) +
		   getSumUtil(mid+1, se, qs, qe, 2*si+2);
}

// Return sum of elements in range from index qs (query
// start) to qe (query end).  It mainly uses getSumUtil()
int getSum(int n, int qs, int qe)
{
	// Check for erroneous input values
	if (qs < 0 || qe > n-1 || qs > qe)
	{
		printf("Invalid Input");
		return -1;
	}
	
	return getSumUtil(0, n-1, qs, qe, 0);
}

// A recursive function that constructs Segment Tree for
//  array[ss..se]. si is index of current node in segment
// tree st.
void constructSTUtil(int ss, int se, int si)
{
	// out of range as ss can never be greater than se
	if (ss > se)
		return ;
	
	// If there is one element in array, store it in
	// current node of segment tree and return
	if (ss == se)
	{
//		tree[si] = arr[ss];
		return;
	}
	
	// If there are more than one elements, then recur
	// for left and right subtrees and store the sum
	// of values in this node
	int mid = (ss + se)/2;
	constructSTUtil(ss, mid, si*2+1);
	constructSTUtil(mid+1, se, si*2+2);
	
	tree[si] = tree[si*2 + 1] + tree[si*2 + 2];
}

/* Function to construct segment tree from given array.
   This function allocates memory for segment tree and
   calls constructSTUtil() to fill the allocated memory */
void constructST(int n)
{
	// Fill the allocated memory st
	constructSTUtil(0, n-1, 0);
}



int main() {
	ios_base::sync_with_stdio(false); cin.tie(NULL);
	int n;
	cin >> n;
	int t;
//	int min = 0;
	int total = 0;
	constructST(n);
//	updateRange(0, 0, n,
	rep(i, 0, n) {
		cin >> t;
		t--;
		a[i] = t;
//		v[t] = true;
//		total++;
	}
//	build(0, 0, n-1);
	
	int mx = -1000000001;
	int sol = 0;
	sRep(i, n-1, 0) {
//		int v = query(0, 0, n-1, a[i], a[i]);
		updateRange(n, a[i], a[i], 1);
		int lessThan = getSum(n, 0, a[i]);
//		dump(lessThan);
		if (lessThan == a[i] + 1) {
			sol++;
		}
		
		
	}

	cout << sol << '\n';
		
	
	return 0;
}

Measured memory_bytes: 6400