/* *****fireice**** */

#include<bits/stdc++.h>

#define ll long long int
#define ld long double
#define vi vector<int>
#define vc vector<char>
#define vl vector<ll>
#define vii vector<pair<int,int>>
#define vll vector<pair<ll,ll>>
#define pii pair<int,int>
#define pb push_back
#define eb emplace_back
#define el '\n'
#define N 1000000007
#define M 2147483647
#define MM 1e18;
#define re return
#define F first
#define S second
#define L length
#define deb(x) cout<<#x<<" "<<x<<el;
#define mp make_pair
#define con continue
#define PI 3.14159265
#define all(a) (a).begin(),(a).end()
#define forup(i,n) for(int i=0;i<n;i++)
#define forf(i,x,n) for(int i=x;i<n;i++)
#define ford(i,n) for(int (i)=(n)-1;i>=0;(i)--)
#define take(a,n) forup(i,n) cin>>a[i];
using namespace std;

int gcdExtended(int a, int b, int *x, int *y)
{
    // Base Case
    if (a == 0)
    {
        *x = 0, *y = 1;
        return b;
    }

    int x1, y1; // To store results of recursive call
    int gcd = gcdExtended(b%a, a, &x1, &y1);

    // Update x and y using results of recursive
    // call
    *x = y1 - (b/a) * x1;
    *y = x1;

    return gcd;
}

ll modInverse(int a, int m)
{
    int x, y;
    int g = gcdExtended(a, m, &x, &y);
        // m is added to handle negative x
    ll res = ((ll)x%m + (ll)m) % m;

    return res;
}

ll poww(ll x,ll n)
{
    if(n==0)
        return 1;
    else if(n==1) return x;
    else if(n%2 == 0)        //n is even
        return poww(x*x,n/2);
    else                              //n is odd
        return x*poww(x*x,(n-1)/2);
}

ll modularExponentiation(ll x,ll n,ll Z)
{
    ll result=1;
    while(n>0)
    {
        if(n % 2 ==1)
            result=(result * x)%Z;
        x=(x*x)%Z;
        n=n/2;
    }
    return result;
}

template<typename T>
T maxx(T a,T b)
{
  if(a<b) re b;
  re a;
}
template<typename T, typename... Args>
T maxx(T a,T b, Args... args)
{
    re(maxx(maxx(a,b),args...));
}

template<typename T>
T minn(T a,T b)
{
  if(a<b) re a;
  re b;
}
template<typename T, typename... Args>
T minn(T a,T b, Args... args)
{
    re(minn(minn(a,b),args...));
}

template<typename T>
void read(T& a)
{
  cin>>a;
}
template<typename T, typename... Args>
void read(T& a,Args&... args)
{
  cin>>a; read(args...);
}

template<typename T>
void write(T a)
{
  cout<<a<<' ';
}
template<typename T, typename... Args>
void write(T a,Args... args)
{
  cout<<a<<' '; write(args...);
}

inline ll min(ll a,ll b)
{
  if(a<b) re a;
  else re b;
}
inline ll max(ll a,ll b)
{
  if(a<b) re b;
  else re a;
}

ll gcd(ll a, ll b)
{
    if (a == 0)
       return b;
    if (b == 0)
       return a;

    if (a == b)
        return a;

    if (a > b)
        return gcd(a-b, b);
    else return gcd(a, b-a);
}

ll ncr(int n,int r)
{
  ll ans=1;
  r=min(r,n-r);
  forup(i,r)
  {
    ans=((ans*((n-i)%N))%N*modInverse(i+1,N))%N;
  }
  re ans;
}

int main()
{
  ios::sync_with_stdio(false);
  cin.tie(NULL);

  int t=1;
  //cin>>t;
  while(t--)
  {
    ll n,m,k;
    // cin>>n;
    string s;
    cin>>s;
    string y="ZONe";
    m=0;
    forup(i,s.L()-3)
    {
      if(s.substr(i,4)==y) m++;
    }
    cout<<m<<el;

  }


  return 0;
}

#include <bits/stdc++.h>
#include <math.h>
using namespace std;
typedef long long ll;
typedef long double ld;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)
const ll mod = 1000000007;
const ll mod9 = 998244353;
const ll INF = 1001001001;
const ll LINF = 1001001001001001001;

void prvec(vector<ll> vec){
    ll n = vec.size();
    rep(i,n) cout << i << " " << vec.at(i) << "\n";
}

void prvec_won(vector<ll> vec){
    ll n = vec.size();
    rep(i,n) cout << vec.at(i) << " ";
    cout << endl;
}

void pr2d(vector<vector<ll>> vvec){
    ll h = vvec.size();
    ll w = vvec.at(0).size();
    rep(i,h){
        rep(j,w){
            cout << vvec.at(i).at(j) << " ";
        }
        cout << "\n";
    }
}

void deb_mk(ll n){
    cout << "debug " << n << endl; 
}

struct SegmentTree {
    int n;
    vector<ll> node;
    //int nとvector<int> nodeの2つを変数に持つ

    //初期化処理
    SegmentTree(vector<ll> v) {
        int sz = v.size(); //szは扱う配列の長さ
        n = 1; while(n < sz) n *= 2; //nはvの配列を入れるために必要なseg treeの葉の数
        node.resize(2*n-1, 0); //segtreeでは全部で2n-1の配列が必要
        for(int i=0; i<sz; i++) node[i+n-1] = v[i]; //segtreeの葉の部分に扱う配列を埋め込む
        for(int i=n-2; i>=0; i--) node[i] = node[2*i+1]^node[2*i+2]; //演算によって変える場所　segtreeを作る(注目しているnode iの子ノードを見て二項演算をして、node iの値を決定する)
    }

    void update(int x, int val) {
        x += (n - 1); //配列のx番目(1-indexed)の要素を更新しようとするとき、segtreeで対応する要素はx+n-1(0-indexed)番目である
        node[x] = val; //segtree上で値を更新
        while(x > 0) { //葉から根に向かってsegtreeの要素を更新していく
            x = (x - 1) / 2;
            node[x] = node[2*x+1]^node[2*x+2]; //演算によって変える
        }
    }

    int getxor(int a, int b, int k=0, int l=0, int r=-1) {
        //求めたいのは区間[a,b)の中で演算しつづけた結果(たとえばこの区間の最小値)
        //自分がいるノードのindex(何階にいるか？)
        //ノードkは元の配列でいうとどの区間をカバーしているか？
        if(r < 0) r = n; //最初に呼び出す時はノードk=0はsegtreeの根なので区間は[0,n)を指す
        if(r <= a || b <= l) return 0; //今のノードが求める区間と無関係の場合は、最終的な答えに影響しない単位元(最小値を求めたい場合は単位元はINF)を返す 演算によって変える
        if(a <= l && r <= b) return node[k]; //今見ている区間[l,r)が答えを求めたい区間[a,b)に完全に含まれるなら、この区間について演算し続けた結果(=node[k];例えば最小値)を返す

        //上記に当てはまらない場合
        //kの子ノードを見に行って、再帰的に処理を行う k=0の場合はノード1と2を見る
        int vl = getxor(a, b, 2*k+1, l, (l+r)/2); //kの子ノード(left)の子孫のうち、求めたい区間に含まれる要素について演算し続けた結果を返す
        int vr = getxor(a, b, 2*k+2, (l+r)/2, r); //kの子ノード(right)の子孫のうち、求めたい区間に含まれる要素について演算し続けた結果を返す
        return vl^vr; //演算によって変える場所 子ノードの子孫のうち、演算しつづけた結果を返す
    }
};

int main(){
    ll nn , q; cin >> nn >> q;
    vector<ll> a(nn);
    rep(i,nn) cin >> a.at(i);
    SegmentTree tree(a);

    rep(i,q){
        ll t,x,y; cin >> t >> x >> y;
        if(t==1){
            tree.update(x-1,(tree.node.at(x-1+ (tree.n) -1))^y);
        }else{
            cout << tree.getxor(x-1,y) << endl;
        }
      	//prvec_won(tree.node);
    }
    return 0;
}