#include <bits/stdc++.h>

#define int long long

using namespace std;

#ifdef LOCAL
#include "/media/brayand/BrayanD/debugger.h"
#else
#define db(...) false
#define dbl(...) false
#define dbg(...) false
#endif

int N, M, X;

typedef long long ll;

template<typename T, typename F>
struct SEGMENT_TREE
{
    ll Li, Ri;

    int pt = 0;

    vector<T> ST;
    vector<int> L;
    vector<int> R;
    vector<bool> lazy;

    void new_node()
    {
        ST.push_back(T{});
        L.push_back(0);
        R.push_back(0);
        lazy.push_back(false);
    }

    SEGMENT_TREE(ll a, ll b)
    {
        assert(a <= b);
        Li = a, Ri = b;
        new_node();
    }

    void build(vector<T> &vect)
    {
        assert(Ri-Li+1 == (ll)vect.size());
        ST_build(0,Li,Ri,vect);
    }

    void insert(ll x, T nod)
    {
        ST_insert(0,Li,Ri,x,nod);
    }

    void update(ll x, F &up)
    {
        ST_update(0,Li,Ri,x,x,up);
    }

    void update(ll a, ll b, F &up)
    {
        ST_update(0,Li,Ri,a,b,up);
    }

    T query(ll x)
    {
        return ST_query(0,Li,Ri,x,x);
    }

    T query(ll a, ll b)
    {
        return ST_query(0,Li,Ri,a,b);
    }

    void ST_build(int node, ll l, ll r, vector<T> &vect)
    {
        if(l == r)
        {
            ST[node] = vect[l-Li];
            return;
        }
        else
        {
            L[node] = ++pt;
            new_node();
            R[node] = ++pt;
            new_node();
        }

        ll mid = (l+r)/2;

        ST_build(L[node],l,mid,vect);
        ST_build(R[node],mid+1,r,vect);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_insert(int node, ll l, ll r, ll x, T &nod)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(l == r)
        {
            ST[node] = nod;
            return;
        }

        ll mid = (l+r)/2;

        if(x <= mid)ST_insert(L[node],l,mid,x,nod);
        else ST_insert(R[node],mid+1,r,x,nod);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_update(int node, ll l, ll r, ll a, ll b, F &up)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(r < a || l > b)return;

        if(a <= l && r <= b)
        {
            ST[node].push(up);
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            return;
        }

        ll mid = (l+r)/2;

        ST_update(L[node],l,mid,a,b,up);
        ST_update(R[node],mid+1,r,a,b,up);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    T ST_query(int node, ll l, ll r, ll a, ll b)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(a <= l && r <= b)
        {
            return ST[node];
        }

        ll mid = (l+r)/2;

        T ans;
        bool flag = false;

        if(a <= mid)
        {
            ans = ST_query(L[node],l,mid,a,b);
            flag = true;
        }

        if(b > mid)
        {
            T qu = ST_query(R[node],mid+1,r,a,b);
            if(flag)
            {
                T temp;
                temp.merge(ans,qu);
                ans = temp;
            }
            else swap(qu,ans);
        }

        return ans;
    }
};

struct QUERY
{
    ll sum = 0;
};

struct NODE
{
    ll sum = 0;
    ll tam = 0;
    vector<pair<int,int>> va, vb;

    void merge(NODE &H1, NODE &H2)
    {
        sum = H1.sum + H2.sum;
        tam = H1.tam + H2.tam;

        int pt = 0;

        for(int i = H2.va.size()-1 ; i >= 0 ; i--)
        {
        	while(pt < H1.vb.size() && (H1.vb[pt].first|H2.va[i].first) < X)
        	{
        		pt++;
        	}
        	if(pt < H1.vb.size())
        	{
        		int val = 0;
        		if(i == H2.va.size()-1)val = H2.tam-H2.va[i].second;
        		else val = H2.va[i+1].second-H2.va[i].second;
        		sum += val*(H1.tam-H1.vb[pt].second);
        	}
        }

        va = H1.va;

        int temp = va.back().first;

        for(auto x : H2.va)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		va.push_back({temp, x.second+H1.tam});
        	}
        }

        vb = H2.vb;

        temp = vb.back().first;

        for(auto x : H1.vb)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		vb.push_back({temp, x.second+H2.tam});
        	}
        }
    }
    void push(QUERY &Q)
    {
    }
    void update(ll l, ll r)
    {
    }
    void propagation(NODE &H1, NODE &H2)
    {
    }
};

int32_t main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M >> X;

    SEGMENT_TREE<NODE, QUERY> ST(1,N);

    vector<NODE> vvv;

    for(int i = 1 ; i <= N ; i++)
    {
    	int n;
    	cin >> n;
    	NODE tp;
    	if(n >= X)tp.sum = 1;
    	tp.tam = 1;
    	tp.va.push_back({n,0});
    	tp.vb.push_back({n,0});
    	vvv.push_back(tp);
    }

    ST.build(vvv);

    for(int i = 1 ; i <= M ; i++)
    {
    	int qu;
    	cin >> qu;

    	if(qu == 1)
    	{
    		int x, v;
    		cin >> x >> v;
    		NODE tp;
	    	if(v >= X)tp.sum = 1;
	    	tp.tam = 1;
	    	tp.va.push_back({v,0});
	    	tp.vb.push_back({v,0});
	    	ST.insert(x, tp);
    	}
    	else
    	{
    		int a, b;
    		cin >> a >> b;
    		cout << ST.query(a,b).sum << '\n';
    	}
    }

    return 0;
}


#include <bits/stdc++.h>

#define int long long

using namespace std;

int N, M, X;

const int MMM = 2e5+100;

typedef long long ll;

struct QUERY
{
    ll sum = 0;
};

struct NODE
{
    ll sum = 0;
    ll tam = 0;
    vector<pair<int,int>> va, vb;

    void merge(NODE &H1, NODE &H2)
    {
        sum = H1.sum + H2.sum;
        tam = H1.tam + H2.tam;

        int pt = 0;

        for(int i = H2.va.size()-1 ; i >= 0 ; i--)
        {
            while(pt < H1.vb.size() && (H1.vb[pt].first|H2.va[i].first) < X)
            {
                pt++;
            }
            if(pt < H1.vb.size())
            {
                int val = 0;
                if(i == H2.va.size()-1)val = H2.tam-H2.va[i].second;
                else val = H2.va[i+1].second-H2.va[i].second;
                sum += val*(H1.tam-H1.vb[pt].second);
            }
        }

        va = H1.va;

        int temp = va.back().first;

        for(auto x : H2.va)
        {
            if(temp != (temp|x.first))
            {
                temp = (temp|x.first);
                va.push_back({temp, x.second+H1.tam});
            }
        }

        vb = H2.vb;

        temp = vb.back().first;

        for(auto x : H1.vb)
        {
            if(temp != (temp|x.first))
            {
                temp = (temp|x.first);
                vb.push_back({temp, x.second+H2.tam});
            }
        }
    }
    void push(QUERY &Q)
    {
    }
    void update(ll l, ll r)
    {
    }
    void propagation(NODE &H1, NODE &H2)
    {
    }
};

NODE ST[MMM];
int L[MMM];
int R[MMM];
bool lazy[MMM];

typedef long long ll;

template<typename T, typename F>
struct SEGMENT_TREE
{
    ll Li, Ri;

    int pt = 0;

    T query_res, query_temp;
    bool query_flag;

    void new_node()
    {

    }

    SEGMENT_TREE(ll a, ll b)
    {
        for(int i = 0 ; i < MMM ; i++)
        {
            L[i] = R[i] = 0;
            lazy[i] = false;
        }
        assert(a <= b);
        Li = a, Ri = b;
        new_node();
    }

    void build(vector<T> &vect)
    {
        assert(Ri-Li+1 == (ll)vect.size());
        ST_build(0,Li,Ri,vect);
    }

    void insert(ll x, T nod)
    {
        ST_insert(0,Li,Ri,x,nod);
    }

    void update(ll x, F &up)
    {
        ST_update(0,Li,Ri,x,x,up);
    }

    void update(ll a, ll b, F &up)
    {
        ST_update(0,Li,Ri,a,b,up);
    }

    T query(ll x)
    {
        query_res = T{};
        query_flag = false;
        ST_query(0,Li,Ri,x,x);
        return query_res;
    }

    T query(ll a, ll b)
    {
        query_res = T{};
        query_flag = false;
        ST_query(0,Li,Ri,a,b);
        return query_res;
    }

    void ST_build(int node, ll l, ll r, vector<T> &vect)
    {
        if(l == r)
        {
            ST[node] = vect[l-Li];
            return;
        }
        else
        {
            L[node] = ++pt;
            new_node();
            R[node] = ++pt;
            new_node();
        }

        ll mid = (l+r)/2;

        ST_build(L[node],l,mid,vect);
        ST_build(R[node],mid+1,r,vect);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_insert(int node, ll l, ll r, ll x, T &nod)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(l == r)
        {
            ST[node] = nod;
            return;
        }

        ll mid = (l+r)/2;

        if(x <= mid)ST_insert(L[node],l,mid,x,nod);
        else ST_insert(R[node],mid+1,r,x,nod);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_update(int node, ll l, ll r, ll a, ll b, F &up)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(r < a || l > b)return;

        if(a <= l && r <= b)
        {
            ST[node].push(up);
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            return;
        }

        ll mid = (l+r)/2;

        ST_update(L[node],l,mid,a,b,up);
        ST_update(R[node],mid+1,r,a,b,up);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_query(int node, ll l, ll r, ll a, ll b)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(a <= l && r <= b)
        {
            if(query_flag)
            {
                query_temp = T{};
                query_temp.merge(query_res, ST[node]);
                query_res = query_temp;
            }
            else
            {
                query_res = ST[node];
                query_flag = true;
            }
            return;
        }

        ll mid = (l+r)/2;

        if(a <= mid)ST_query(L[node],l,mid,a,b);
        if(b > mid)ST_query(R[node],mid+1,r,a,b);
    }
};
///

int32_t main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M >> X;

    SEGMENT_TREE<NODE, QUERY> ST(1,N);

    vector<NODE> vvv;

    for(int i = 1 ; i <= N ; i++)
    {
    	int n;
    	cin >> n;
    	NODE tp;
    	if(n >= X)tp.sum = 1;
    	tp.tam = 1;
    	tp.va.push_back({n,0});
    	tp.vb.push_back({n,0});
    	vvv.push_back(tp);
    }

    ST.build(vvv);

    for(int i = 1 ; i <= M ; i++)
    {
    	int qu;
    	cin >> qu;

    	if(qu == 1)
    	{
    		int x, v;
    		cin >> x >> v;
    		NODE tp;
	    	if(v >= X)tp.sum = 1;
	    	tp.tam = 1;
	    	tp.va.push_back({v,0});
	    	tp.vb.push_back({v,0});
	    	ST.insert(x, tp);
    	}
    	else
    	{
    		int a, b;
    		cin >> a >> b;
    		cout << ST.query(a,b).sum << '\n';
    	}
    }

    return 0;
}


#include <bits/stdc++.h>

#define int long long

using namespace std;

#ifdef LOCAL
#include "/media/brayand/BrayanD/debugger.h"
#else
#define db(...) false
#define dbl(...) false
#define dbg(...) false
#endif

int N, M, X;

typedef long long ll;

template<typename T, typename F>
struct SEGMENT_TREE
{
    ll Li, Ri;

    int pt = 0;

    vector<T> ST;
    vector<int> L;
    vector<int> R;
    vector<bool> lazy;

    void new_node()
    {
        ST.push_back(T{});
        L.push_back(0);
        R.push_back(0);
        lazy.push_back(false);
    }

    SEGMENT_TREE(ll a, ll b)
    {
        assert(a <= b);
        Li = a, Ri = b;
        new_node();
    }

    void build(vector<T> &vect)
    {
        assert(Ri-Li+1 == (ll)vect.size());
        ST_build(0,Li,Ri,vect);
    }

    void insert(ll x, T nod)
    {
        ST_insert(0,Li,Ri,x,nod);
    }

    void update(ll x, F &up)
    {
        ST_update(0,Li,Ri,x,x,up);
    }

    void update(ll a, ll b, F &up)
    {
        ST_update(0,Li,Ri,a,b,up);
    }

    T query(ll x)
    {
        return ST_query(0,Li,Ri,x,x);
    }

    T query(ll a, ll b)
    {
        return ST_query(0,Li,Ri,a,b);
    }

    void ST_build(int node, ll l, ll r, vector<T> &vect)
    {
        if(l == r)
        {
            ST[node] = vect[l-Li];
            return;
        }
        else
        {
            L[node] = ++pt;
            new_node();
            R[node] = ++pt;
            new_node();
        }

        ll mid = (l+r)/2;

        ST_build(L[node],l,mid,vect);
        ST_build(R[node],mid+1,r,vect);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_insert(int node, ll l, ll r, ll x, T &nod)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(l == r)
        {
            ST[node] = nod;
            return;
        }

        ll mid = (l+r)/2;

        if(x <= mid)ST_insert(L[node],l,mid,x,nod);
        else ST_insert(R[node],mid+1,r,x,nod);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_update(int node, ll l, ll r, ll a, ll b, F &up)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(r < a || l > b)return;

        if(a <= l && r <= b)
        {
            ST[node].push(up);
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            return;
        }

        ll mid = (l+r)/2;

        ST_update(L[node],l,mid,a,b,up);
        ST_update(R[node],mid+1,r,a,b,up);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    T ST_query(int node, ll l, ll r, ll a, ll b)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(a <= l && r <= b)
        {
            return ST[node];
        }

        ll mid = (l+r)/2;

        T ans;
        bool flag = false;

        if(a <= mid)
        {
            ans = ST_query(L[node],l,mid,a,b);
            flag = true;
        }

        if(b > mid)
        {
            T qu = ST_query(R[node],mid+1,r,a,b);
            if(flag)
            {
                T temp;
                temp.merge(ans,qu);
                ans = temp;
            }
            else swap(qu,ans);
        }

        return ans;
    }
};

///
struct QUERY
{
    ll sum = 0;
};

struct NODE
{
    ll sum = 0;
    ll lazysum = 0;
    void merge(NODE &H1, NODE &H2)
    {
        sum = H1.sum + H2.sum;
    }
    void push(QUERY &Q)
    {
        lazysum = Q.sum;
    }
    void update(ll l, ll r)
    {
        sum += (r-l+1)*lazysum;
        lazysum = 0;
    }
    void propagation(NODE &H1, NODE &H2)
    {
        H1.lazysum += lazysum;
        H2.lazysum += lazysum;
    }
};

struct NODE
{
    ll sum = 0;
    ll tam = 0;
    vector<pair<int,int>> va, vb;

    void merge(NODE &H1, NODE &H2)
    {
        sum = H1.sum + H2.sum;
        tam = H1.tam + H2.tam;

        int pt = 0;

        for(int i = H2.va.size()-1 ; i >= 0 ; i--)
        {
        	while(pt < H1.vb.size() && (H1.vb[pt].first|H2.va[i].first) < X)
        	{
        		pt++;
        	}
        	if(pt < H1.vb.size())
        	{
        		int val = 0;
        		if(i == H2.va.size()-1)val = H2.tam-H2.va[i].second;
        		else val = H2.va[i+1].second-H2.va[i].second;
        		sum += val*(H1.tam-H1.vb[pt].second);
        	}
        }

        va = H1.va;

        int temp = va.back().first;

        for(auto x : H2.va)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		va.push_back({temp, x.second+H1.tam});
        	}
        }

        vb = H2.vb;

        temp = vb.back().first;

        for(auto x : H1.vb)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		vb.push_back({temp, x.second+H2.tam});
        	}
        }
    }
    void push(QUERY &Q)
    {
    }
    void update(ll l, ll r)
    {
    }
    void propagation(NODE &H1, NODE &H2)
    {
    }
};

int32_t main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M >> X;

    SEGMENT_TREE<NODE, QUERY> ST(1,N);

    vector<NODE> vvv;

    for(int i = 1 ; i <= N ; i++)
    {
    	int n;
    	cin >> n;
    	NODE tp;
    	if(n >= X)tp.sum = 1;
    	tp.tam = 1;
    	tp.va.push_back({n,0});
    	tp.vb.push_back({n,0});
    	vvv.push_back(tp);
    }

    ST.build(vvv);

    for(int i = 1 ; i <= M ; i++)
    {
    	int qu;
    	cin >> qu;

    	if(qu == 1)
    	{
    		int x, v;
    		cin >> x >> v;
    		NODE tp;
	    	if(v >= X)tp.sum = 1;
	    	tp.tam = 1;
	    	tp.va.push_back({v,0});
	    	tp.vb.push_back({v,0});
	    	ST.insert(x, tp);
    	}
    	else
    	{
    		int a, b;
    		cin >> a >> b;
    		cout << ST.query(a,b).sum << '\n';
    	}
    }

    return 0;
}


#include <bits/stdc++.h>

#define int long long

using namespace std;

#ifdef LOCAL
#include "/media/brayand/BrayanD/debugger.h"
#else
#define db(...) false
#define dbl(...) false
#define dbg(...) false
#endif

int N, M, X;

typedef long long ll;

template<typename T, typename F>
struct SEGMENT_TREE
{
    ll Li, Ri;

    int pt = 0;

    vector<T> ST;
    vector<int> L;
    vector<int> R;
    vector<bool> lazy;

    void new_node()
    {
        ST.push_back(T{});
        L.push_back(0);
        R.push_back(0);
        lazy.push_back(false);
    }

    SEGMENT_TREE(ll a, ll b)
    {
        assert(a <= b);
        Li = a, Ri = b;
        new_node();
    }

    void build(vector<T> &vect)
    {
        assert(Ri-Li+1 == (ll)vect.size());
        ST_build(0,Li,Ri,vect);
    }

    void insert(ll x, T nod)
    {
        ST_insert(0,Li,Ri,x,nod);
    }

    void update(ll x, F &up)
    {
        ST_update(0,Li,Ri,x,x,up);
    }

    void update(ll a, ll b, F &up)
    {
        ST_update(0,Li,Ri,a,b,up);
    }

    T query(ll x)
    {
        return ST_query(0,Li,Ri,x,x);
    }

    T query(ll a, ll b)
    {
        return ST_query(0,Li,Ri,a,b);
    }

    void ST_build(int node, ll l, ll r, vector<T> &vect)
    {
        if(l == r)
        {
            ST[node] = vect[l-Li];
            return;
        }
        else
        {
            L[node] = ++pt;
            new_node();
            R[node] = ++pt;
            new_node();
        }

        ll mid = (l+r)/2;

        ST_build(L[node],l,mid,vect);
        ST_build(R[node],mid+1,r,vect);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_insert(int node, ll l, ll r, ll x, T &nod)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(l == r)
        {
            ST[node] = nod;
            return;
        }

        ll mid = (l+r)/2;

        if(x <= mid)ST_insert(L[node],l,mid,x,nod);
        else ST_insert(R[node],mid+1,r,x,nod);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_update(int node, ll l, ll r, ll a, ll b, F &up)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(r < a || l > b)return;

        if(a <= l && r <= b)
        {
            ST[node].push(up);
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            return;
        }

        ll mid = (l+r)/2;

        ST_update(L[node],l,mid,a,b,up);
        ST_update(R[node],mid+1,r,a,b,up);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    T ST_query(int node, ll l, ll r, ll a, ll b)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(a <= l && r <= b)
        {
            return ST[node];
        }

        ll mid = (l+r)/2;

        T ans;
        bool flag = false;

        if(a <= mid)
        {
            ans = ST_query(L[node],l,mid,a,b);
            flag = true;
        }

        if(b > mid)
        {
            T qu = ST_query(R[node],mid+1,r,a,b);
            if(flag)
            {
                T temp;
                temp.merge(ans,qu);
                ans = temp;
            }
            else swap(qu,ans);
        }

        return ans;
    }
};

///
struct QUERY
{
    ll sum = 0;
};

struct NODE
{
    ll sum = 0;
    ll tam = 0;
    vector<pair<int,int>> va, vb;

    void merge(NODE &H1, NODE &H2)
    {
        sum = H1.sum + H2.sum;
        tam = H1.tam + H2.tam;

        int pt = 0;

        for(int i = H2.va.size()-1 ; i >= 0 ; i--)
        {
        	while(pt < H1.vb.size() && (H1.vb[pt].first|H2.va[i].first) < X)
        	{
        		pt++;
        	}
        	if(pt < H1.vb.size())
        	{
        		int val = 0;
        		if(i == H2.va.size()-1)val = H2.tam-H2.va[i].second;
        		else val = H2.va[i+1].second-H2.va[i].second;
        		sum += val*(H1.tam-H1.vb[pt].second);
        	}
        }

        va = H1.va;

        int temp = va.back().first;

        for(auto x : H2.va)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		va.push_back({temp, x.second+H1.tam});
        	}
        }

        vb = H2.vb;

        temp = vb.back().first;

        for(auto x : H1.vb)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		vb.push_back({temp, x.second+H2.tam});
        	}
        }
    }
    void push(QUERY &Q)
    {
    }
    void update(ll l, ll r)
    {
    }
    void propagation(NODE &H1, NODE &H2)
    {
    }
};

int32_t main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M >> X;

    SEGMENT_TREE<NODE, QUERY> ST(1,N);

    vector<NODE> vvv;

    for(int i = 1 ; i <= N ; i++)
    {
    	int n;
    	cin >> n;
    	NODE tp;
    	if(n >= X)tp.sum = 1;
    	tp.tam = 1;
    	tp.va.push_back({n,0});
    	tp.vb.push_back({n,0});
    	vvv.push_back(tp);
    }

    ST.build(vvv);

    for(int i = 1 ; i <= M ; i++)
    {
    	int qu;
    	cin >> qu;

    	if(qu == 1)
    	{
    		int x, v;
    		cin >> x >> v;
    		NODE tp;
	    	if(v >= X)tp.sum = 1;
	    	tp.tam = 1;
	    	tp.va.push_back({v,0});
	    	tp.vb.push_back({v,0});
	    	ST.insert(x, tp);
    	}
    	else
    	{
    		int a, b;
    		cin >> a >> b;
    		cout << ST.query(a,b).sum << '\n';
    	}
    }

    return 0;
}


#include <bits/stdc++.h>

#define int long long

using namespace std;

int N, M, X;

typedef long long ll;

template<typename T, typename F>
struct SEGMENT_TREE
{
    ll Li, Ri;

    int pt = 0;

    vector<T> ST;
    vector<int> L;
    vector<int> R;
    vector<bool> lazy;

    T query_res, query_temp;
    bool query_flag;

    void new_node()
    {
        ST.push_back(T{});
        L.push_back(0);
        R.push_back(0);
        lazy.push_back(false);
    }

    SEGMENT_TREE(ll a, ll b)
    {
        assert(a <= b);
        Li = a, Ri = b;
        new_node();
    }

    void build(vector<T> &vect)
    {
        assert(Ri-Li+1 == (ll)vect.size());
        ST_build(0,Li,Ri,vect);
    }

    void insert(ll x, T nod)
    {
        ST_insert(0,Li,Ri,x,nod);
    }

    void update(ll x, F &up)
    {
        ST_update(0,Li,Ri,x,x,up);
    }

    void update(ll a, ll b, F &up)
    {
        ST_update(0,Li,Ri,a,b,up);
    }

    T query(ll x)
    {
        query_res = T{};
        query_flag = false;
        ST_query(0,Li,Ri,x,x);
        return query_res;
    }

    T query(ll a, ll b)
    {
        query_res = T{};
        query_flag = false;
        ST_query(0,Li,Ri,a,b);
        return query_res;
    }

    void ST_build(int node, ll l, ll r, vector<T> &vect)
    {
        if(l == r)
        {
            ST[node] = vect[l-Li];
            return;
        }
        else
        {
            L[node] = ++pt;
            new_node();
            R[node] = ++pt;
            new_node();
        }

        ll mid = (l+r)/2;

        ST_build(L[node],l,mid,vect);
        ST_build(R[node],mid+1,r,vect);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_insert(int node, ll l, ll r, ll x, T &nod)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(l == r)
        {
            ST[node] = nod;
            return;
        }

        ll mid = (l+r)/2;

        if(x <= mid)ST_insert(L[node],l,mid,x,nod);
        else ST_insert(R[node],mid+1,r,x,nod);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_update(int node, ll l, ll r, ll a, ll b, F &up)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(r < a || l > b)return;

        if(a <= l && r <= b)
        {
            ST[node].push(up);
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            return;
        }

        ll mid = (l+r)/2;

        ST_update(L[node],l,mid,a,b,up);
        ST_update(R[node],mid+1,r,a,b,up);

        ST[node].merge(ST[L[node]],ST[R[node]]);
    }

    void ST_query(int node, ll l, ll r, ll a, ll b)
    {
        if(l != r)
        {
            if(L[node] == 0)
            {
                L[node] = ++pt;
                new_node();
            }
            if(R[node] == 0)
            {
                R[node] = ++pt;
                new_node();
            }
        }

        if(lazy[node])
        {
            if(l != r)
            {
                ST[node].propagation(ST[L[node]],ST[R[node]]);
                lazy[L[node]] = true;
                lazy[R[node]] = true;
            }
            ST[node].update(l,r);
            lazy[node] = false;
        }

        if(a <= l && r <= b)
        {
            if(query_flag)
            {
                query_temp = T{};
                query_temp.merge(query_res, ST[node]);
                query_res = query_temp;
            }
            else
            {
                query_res = ST[node];
                query_flag = true;
            }
            return;
        }

        ll mid = (l+r)/2;

        if(a <= mid)ST_query(L[node],l,mid,a,b);
        if(b > mid)ST_query(R[node],mid+1,r,a,b);
    }
};
///
struct QUERY
{
    ll sum = 0;
};

struct NODE
{
    ll sum = 0;
    ll tam = 0;
    vector<pair<int,int>> va, vb;

    void merge(NODE &H1, NODE &H2)
    {
        sum = H1.sum + H2.sum;
        tam = H1.tam + H2.tam;

        int pt = 0;

        for(int i = H2.va.size()-1 ; i >= 0 ; i--)
        {
        	while(pt < H1.vb.size() && (H1.vb[pt].first|H2.va[i].first) < X)
        	{
        		pt++;
        	}
        	if(pt < H1.vb.size())
        	{
        		int val = 0;
        		if(i == H2.va.size()-1)val = H2.tam-H2.va[i].second;
        		else val = H2.va[i+1].second-H2.va[i].second;
        		sum += val*(H1.tam-H1.vb[pt].second);
        	}
        }

        va = H1.va;

        int temp = va.back().first;

        for(auto x : H2.va)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		va.push_back({temp, x.second+H1.tam});
        	}
        }

        vb = H2.vb;

        temp = vb.back().first;

        for(auto x : H1.vb)
        {
        	if(temp != (temp|x.first))
        	{
        		temp = (temp|x.first);
        		vb.push_back({temp, x.second+H2.tam});
        	}
        }
    }
    void push(QUERY &Q)
    {
    }
    void update(ll l, ll r)
    {
    }
    void propagation(NODE &H1, NODE &H2)
    {
    }
};

int32_t main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);

    cin >> N >> M >> X;

    SEGMENT_TREE<NODE, QUERY> ST(1,N);

    vector<NODE> vvv;

    for(int i = 1 ; i <= N ; i++)
    {
    	int n;
    	cin >> n;
    	NODE tp;
    	if(n >= X)tp.sum = 1;
    	tp.tam = 1;
    	tp.va.push_back({n,0});
    	tp.vb.push_back({n,0});
    	vvv.push_back(tp);
    }

    ST.build(vvv);

    for(int i = 1 ; i <= M ; i++)
    {
    	int qu;
    	cin >> qu;

    	if(qu == 1)
    	{
    		int x, v;
    		cin >> x >> v;
    		NODE tp;
	    	if(v >= X)tp.sum = 1;
	    	tp.tam = 1;
	    	tp.va.push_back({v,0});
	    	tp.vb.push_back({v,0});
	    	ST.insert(x, tp);
    	}
    	else
    	{
    		int a, b;
    		cin >> a >> b;
    		cout << ST.query(a,b).sum << '\n';
    	}
    }

    return 0;
}


#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cctype>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
#include<sstream>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<list>
#include<deque>
#include<bitset>
#include<fstream>
#define ld double
#define ull unsigned long long
#define ll long long
#define pii pair<int,int >
#define iiii pair<int,pii >
#define mp make_pair
#define INF 1000000000
#define MOD 1000000007
#define rep(i,x) for(int (i)=0;(i)<(x);(i)++)
inline int getint(){
    int x=0,p=1;char c=getchar();
    while (c<=32)c=getchar();
    if(c==45)p=-p,c=getchar();
    while (c>32)x=x*10+c-48,c=getchar();
    return x*p;
}
using namespace std;
//ruogu
const int N=1e5+10;
const int M=(1<<20)+10;
int n,m,q,a[N];
bool ok[20];
vector<int>to[M];
inline void umax(int &x,int y){
	if(y>x)x=y;
}
inline void umin(int &x,int y){
	if(y<x)x=y;
}
struct D{
	int l,r;
	ll res;
	vector<pii >ls,rs;
	D(){res=0ll;l=INF,r=-INF;ls.clear();rs.clear();}
	inline void update(int p,int _x){
		l=p;r=p+1;
		ls.clear();rs.clear();
		if(_x>=m)res=1ll;
		else res=0ll;
		ls.emplace_back(p,_x);
		rs.emplace_back(p,_x);
	}
	inline D operator +(const D &b)const{
		if(l==INF)return b;
		if(b.l==INF)return (*this);
		D ans;
		ans.l=l;ans.r=b.r;
		//get ans.res
		ans.res=res+b.res;
		int mk0=0,mk1=0;
		int p=b.ls.size()-1;
		rep(i,b.ls.size())mk1|=b.ls[i].second;
		for(int i=rs.size()-1;i>=0;i--){
			mk0|=rs[i].second;
			if((mk0|mk1)<m)continue;
			while(p>0&&((mk1^b.ls[p].second)|mk0)>=m){
				p--;
				mk1^=b.ls[p+1].second;
			}
			int len=rs[i].first-ans.l+1;
			if(i>0)len=rs[i].first-rs[i-1].first;
			ans.res+=1ll*len*(ans.r-b.ls[p].first);
		}
		//get ans.ls
		if(ls.begin()->first!=ans.l)ans.ls.emplace_back(ans.l,0);
		memset(ok,0,sizeof(ok));
		rep(i,ls.size()){
			ans.ls.emplace_back(ls[i]);
			rep(j,to[ls[i].second].size())ok[to[ls[i].second][j]]=true;
		}
		rep(i,b.ls.size()){
			pii u=b.ls[i];
			rep(j,to[u.second].size())if(ok[to[u.second][j]])u.second^=(1<<to[u.second][j]);
			if(u.second)ans.ls.emplace_back(u);
		}
		//get ans.rs
		memset(ok,0,sizeof(ok));
		for(int i=b.rs.size()-1;i>=0;i--){
			ans.rs.emplace_back(b.rs[i]);
			rep(j,to[b.rs[i].second].size())ok[to[b.rs[i].second][j]]=true;
		}
		for(int i=rs.size()-1;i>=0;i--){
			pii u=rs[i];
			rep(j,to[u.second].size())if(ok[to[u.second][j]])u.second^=(1<<to[u.second][j]);
			if(u.second)ans.rs.emplace_back(u);
		}
		if(b.rs.rbegin()->first!=ans.r-1)ans.rs.emplace_back(ans.r-1,0);
		reverse(ans.rs.begin(),ans.rs.end());
		return ans;
	}
}dat[N<<2];
//
void build(int l,int r,int k){
	if(r-l==1){
		dat[k].update(l,a[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,2*k+1);
	build(mid,r,2*k+2);
	dat[k]=dat[2*k+1]+dat[2*k+2];
}
void modify(int l,int r,int p,int k,int x){
	if(r-l==1){
		dat[k].update(l,x);
		return;
	}
	int mid=(l+r)>>1;
	if(p<mid)modify(l,mid,p,2*k+1,x);
	else modify(mid,r,p,2*k+2,x);
	dat[k]=dat[2*k+1]+dat[2*k+2];
}
D qry(int l,int r,int x,int y,int k){
	if(l>=y||x>=r)return D();
	if(x<=l&&r<=y)return dat[k];
	int mid=(l+r)>>1;
	return qry(l,mid,x,y,2*k+1)+qry(mid,r,x,y,2*k+2);
}
int main(){
	rep(i,M)rep(j,20)if(i>>j&1)to[i].push_back(j);
	n=getint();q=getint();m=getint();
	rep(i,n)a[i]=getint();
	build(0,n,0);
	rep(qqq,q){
		int op=getint(),x=getint()-1,y=getint();
		if(op==1)modify(0,n,x,0,y);
		else printf("%lld\n",qry(0,n,x,y,0).res);
	}
	return 0;
}


#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cctype>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
#include<sstream>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<list>
#include<deque>
#include<bitset>
#include<fstream>
#define ld double
#define ull unsigned long long
#define ll long long
#define pii pair<int,int >
#define iiii pair<int,pii >
#define mp make_pair
#define INF 1000000000
#define MOD 1000000007
#define rep(i,x) for(int (i)=0;(i)<(x);(i)++)
inline int getint(){
    int x=0,p=1;char c=getchar();
    while (c<=32)c=getchar();
    if(c==45)p=-p,c=getchar();
    while (c>32)x=x*10+c-48,c=getchar();
    return x*p;
}
using namespace std;
//ruogu
const int N=1e5+10;
const int M=(1<<20)+10;
int n,m,q,a[N];
bool ok[20];
vector<int>to[M];
inline void umax(int &x,int y){
	if(y>x)x=y;
}
inline void umin(int &x,int y){
	if(y<x)x=y;
}
struct D{
	int l,r;
	ll res;
	vector<pii >ls,rs;
	D(){res=0ll;l=INF,r=-INF;ls.clear();rs.clear();}
	inline void update(int p,int _x){
		l=p;r=p+1;
		ls.clear();rs.clear();
		if(_x>=m)res=1ll;
		else res=0ll;
		ls.emplace_back(p,_x);
		rs.emplace_back(p,_x);
	}
	inline D operator +(const D &b)const{
		if(l==INF)return b;
		if(b.l==INF)return (*this);
		D ans;
		ans.l=l;ans.r=b.r;
		//get ans.res
		ans.res=res+b.res;
		int mk0=0,mk1=0;
		int p=b.ls.size()-1;
		rep(i,b.ls.size())mk1|=b.ls[i].second;
		for(int i=rs.size()-1;i>=0;i--){
			mk0|=rs[i].second;
			if((mk0|mk1)<m)continue;
			while(p>0&&((mk1^b.ls[p].second)|mk0)>=m){
				p--;
				mk1^=b.ls[p+1].second;
			}
			int len=rs[i].first-ans.l+1;
			if(i>0)len=rs[i].first-rs[i-1].first;
			ans.res+=1ll*len*(ans.r-b.ls[p].first);
		}
		//get ans.ls
		if(ls.begin()->first!=ans.l)ans.ls.emplace_back(ans.l,0);
		memset(ok,0,sizeof(ok));
		rep(i,ls.size()){
			ans.ls.emplace_back(ls[i]);
			rep(j,to[ls[i].second].size())ok[to[ls[i].second][j]]=true;
		}
		rep(i,b.ls.size()){
			pii u=b.ls[i];
			rep(j,to[u.second].size())if(ok[to[u.second][j]])u.second^=(1<<to[u.second][j]);
			if(u.second)ans.ls.emplace_back(u);
		}
		//get ans.rs
		memset(ok,0,sizeof(ok));
		if(b.rs.rbegin()->first!=ans.r-1)ans.rs.emplace_back(ans.r-1,0);
		for(int i=b.rs.size()-1;i>=0;i--){
			ans.rs.emplace_back(b.rs[i]);
			rep(j,to[b.rs[i].second].size())ok[to[b.rs[i].second][j]]=true;
		}
		for(int i=rs.size()-1;i>=0;i--){
			pii u=rs[i];
			rep(j,to[u.second].size())if(ok[to[u.second][j]])u.second^=(1<<to[u.second][j]);
			if(u.second)ans.rs.emplace_back(u);
		}
		reverse(ans.rs.begin(),ans.rs.end());
		return ans;
	}
}dat[N<<2];
//
void build(int l,int r,int k){
	if(r-l==1){
		dat[k].update(l,a[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,2*k+1);
	build(mid,r,2*k+2);
	dat[k]=dat[2*k+1]+dat[2*k+2];
}
void modify(int l,int r,int p,int k,int x){
	if(r-l==1){
		dat[k].update(l,x);
		return;
	}
	int mid=(l+r)>>1;
	if(p<mid)modify(l,mid,p,2*k+1,x);
	else modify(mid,r,p,2*k+2,x);
	dat[k]=dat[2*k+1]+dat[2*k+2];
}
D qry(int l,int r,int x,int y,int k){
	if(l>=y||x>=r)return D();
	if(x<=l&&r<=y)return dat[k];
	int mid=(l+r)>>1;
	return qry(l,mid,x,y,2*k+1)+qry(mid,r,x,y,2*k+2);
}
int main(){
	rep(i,M)rep(j,20)if(i>>j&1)to[i].push_back(j);
	n=getint();q=getint();m=getint();
	rep(i,n)a[i]=getint();
	build(0,n,0);
	rep(qqq,q){
		int op=getint(),x=getint()-1,y=getint();
		if(op==1)modify(0,n,x,0,y);
		else printf("%lld\n",qry(0,n,x,y,0).res);
	}
	return 0;
}


#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cctype>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
#include<sstream>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<list>
#include<deque>
#include<bitset>
#include<fstream>
#include<assert.h>
#define ld double
#define ull unsigned long long
#define ll long long
#define pii pair<int,int >
#define iiii pair<int,pii >
#define mp make_pair
#define INF 1000000000
#define MOD 1000000007
#define rep(i,x) for(int (i)=0;(i)<(x);(i)++)
inline int getint(){
    int x=0,p=1;char c=getchar();
    while (c<=32)c=getchar();
    if(c==45)p=-p,c=getchar();
    while (c>32)x=x*10+c-48,c=getchar();
    return x*p;
}
using namespace std;
//ruogu
const int N=1e5+10;
const int M=(1<<20)+10;
int n,m,q,a[N];
bool ok[20];
vector<int>to[M];
inline void umax(int &x,int y){
	if(y>x)x=y;
}
inline void umin(int &x,int y){
	if(y<x)x=y;
}
struct D{
	int l,r;
	ll res;
	vector<pii >ls,rs;
	D(){res=0ll;l=INF,r=-INF;ls.clear();rs.clear();}
	inline void update(int p,int _x){
		l=p;r=p+1;
		ls.clear();rs.clear();
		if(_x>=m)res=1ll;
		else res=0ll;
		ls.emplace_back(p,_x);
		rs.emplace_back(p,_x);
	}
	inline D operator +(const D &b)const{
		if(l==INF)return b;
		if(b.l==INF)return (*this);
		D ans;
		ans.l=l;ans.r=b.r;
		//get ans.res
		ans.res=res+b.res;
		int mk0=0,mk1=0;
		int p=b.ls.size()-1;
		rep(i,b.ls.size())mk1|=b.ls[i].second;
		for(int i=rs.size()-1;i>=0;i--){
			mk0|=rs[i].second;
			if((mk0|mk1)<m)continue;
			while(p>0&&((mk1^b.ls[p].second)|mk0)>=m){
				p--;
				mk1^=b.ls[p+1].second;
			}
			int len=rs[i].first-ans.l+1;
			if(i>0)len=rs[i].first-rs[i-1].first;
			ans.res+=1ll*len*(ans.r-b.ls[p].first);
		}
		//get ans.ls
		memset(ok,0,sizeof(ok));
		rep(i,ls.size()){
			ans.ls.emplace_back(ls[i]);
			rep(j,to[ls[i].second].size())ok[to[ls[i].second][j]]=true;
		}
		rep(i,b.ls.size()){
			pii u=b.ls[i];
			int x=u.second;
			rep(j,to[x].size())if(ok[to[x][j]])u.second^=(1<<to[x][j]);
			if(u.second)ans.ls.emplace_back(u);
		}
		assert(ans.ls.begin()->first==ans.l);
		//get ans.rs
		memset(ok,0,sizeof(ok));
		for(int i=b.rs.size()-1;i>=0;i--){
			ans.rs.emplace_back(b.rs[i]);
			rep(j,to[b.rs[i].second].size())ok[to[b.rs[i].second][j]]=true;
		}
		for(int i=rs.size()-1;i>=0;i--){
			pii u=rs[i];
			int x=u.second;
			rep(j,to[u.second].size())if(ok[to[x][j]])u.second^=(1<<to[x][j]);
			if(u.second)ans.rs.emplace_back(u);
		}
		reverse(ans.rs.begin(),ans.rs.end());
		assert(ans.rs.rbegin()->first==ans.r-1);
		return ans;
	}
}dat[N<<2];
//
void build(int l,int r,int k){
	if(r-l==1){
		dat[k].update(l,a[l]);
	//	cout<<l<<" "<<r<<" "<<dat[k].res<<endl;
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,2*k+1);
	build(mid,r,2*k+2);
	dat[k]=dat[2*k+1]+dat[2*k+2];
	//cout<<l<<" "<<r<<" "<<dat[k].res<<endl;
}
void modify(int l,int r,int p,int k,int x){
	if(r-l==1){
		dat[k].update(l,x);
		return;
	}
	int mid=(l+r)>>1;
	if(p<mid)modify(l,mid,p,2*k+1,x);
	else modify(mid,r,p,2*k+2,x);
	dat[k]=dat[2*k+1]+dat[2*k+2];
}
D qry(int l,int r,int x,int y,int k){
	if(l>=y||x>=r)return D();
	if(x<=l&&r<=y)return dat[k];
	int mid=(l+r)>>1;
	return qry(l,mid,x,y,2*k+1)+qry(mid,r,x,y,2*k+2);
}
int main(){
	rep(i,M)rep(j,20)if(i>>j&1)to[i].push_back(j);
	n=getint();q=getint();m=getint();
	rep(i,n)a[i]=getint();
	build(0,n,0);
	rep(qqq,q){
		//cout<<qqq<<"-----------\n";
		int op=getint(),x=getint()-1,y=getint();
		if(op==1)modify(0,n,x,0,y);
		else printf("%lld\n",qry(0,n,x,y,0).res);
	}
	return 0;
}


#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<cctype>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<iomanip>
#include<sstream>
#include<vector>
#include<cstdlib>
#include<ctime>
#include<list>
#include<deque>
#include<bitset>
#include<fstream>
#define ld double
#define ull unsigned long long
#define ll long long
#define pii pair<int,int >
#define iiii pair<int,pii >
#define mp make_pair
#define INF 1000000000
#define MOD 1000000007
#define rep(i,x) for(int (i)=0;(i)<(x);(i)++)
inline int getint(){
    int x=0,p=1;char c=getchar();
    while (c<=32)c=getchar();
    if(c==45)p=-p,c=getchar();
    while (c>32)x=x*10+c-48,c=getchar();
    return x*p;
}
using namespace std;
//ruogu
const int N=1e5+10;
int n,m,q,a[N];
vector<pii >mL,mR;
vector<pii >::iterator it;
inline void umax(int &x,int y){
	if(y>x)x=y;
}
inline void umin(int &x,int y){
	if(y<x)x=y;
}
struct D{
	int l,r,L[20],R[20];
	ll res;
	vector<pii >ls,rs;
	D(){res=0ll;l=INF,r=-INF;ls.clear();rs.clear();rep(i,20)L[i]=INF,R[i]=-INF;}
	inline void update(int p,int _x){
		l=p;r=p+1;
		ls.clear();rs.clear();
		if(_x>=m)res=1ll;
		else res=0ll;
		ls.emplace_back(p,_x);
		rs.emplace_back(p,_x);
		rep(i,20)if(_x>>i&1)L[i]=R[i]=p;
		else L[i]=INF,R[i]=-INF;
	}
	inline D operator +(const D &b)const{
		if(l==INF)return b;
		if(b.l==INF)return (*this);
		D ans;
		ans.l=l;ans.r=b.r;
		//get ans.res
		ans.res=res+b.res;
		int mk0=0,mk1=0;
		int p=b.ls.size()-1;
		rep(i,b.ls.size())mk1|=b.ls[i].second;
		for(int i=rs.size()-1;i>=0;i--){
			mk0|=rs[i].second;
			if((mk0|mk1)<m)continue;
			while(p>0&&((mk1^b.ls[p].second)|mk0)>=m){
				p--;
				mk1^=b.ls[p+1].second;
			}
			int len=rs[i].first-ans.l+1;
			if(i>0)len=rs[i].first-rs[i-1].first;
			ans.res+=1ll*len*(ans.r-b.ls[p].first);
		}
		//get ans.ls,rs and ans.L,R
		mL.clear();mR.clear();
		rep(i,20){
			ans.L[i]=min(L[i],b.L[i]);
			ans.R[i]=max(R[i],b.R[i]);
			if(ans.L[i]!=INF)mL.emplace_back(ans.L[i],1<<i);
			if(ans.R[i]!=-INF)mR.emplace_back(ans.R[i],1<<i);
		}
		sort(mL.begin(),mL.end());
		sort(mR.begin(),mR.end());
		if(mL.empty()||mL.begin()->first!=ans.l)ans.ls.emplace_back(ans.l,0);
		for(it=mL.begin();it!=mL.end();it++){
			if(!ans.ls.empty()&&it->first==ans.ls.back().first)ans.ls.back().second|=it->second;
			else ans.ls.push_back(*it);
		}
		for(it=mR.begin();it!=mR.end();it++){
			if(!ans.rs.empty()&&it->first==ans.rs.back().first)ans.rs.back().second|=it->second;
			else ans.rs.push_back(*it);
		}
		if(mR.empty()||mR.back().first!=ans.r-1)ans.rs.emplace_back(ans.r-1,0);
		return ans;
	}
}dat[N<<2];
//
void build(int l,int r,int k){
	if(r-l==1){
		dat[k].update(l,a[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,2*k+1);
	build(mid,r,2*k+2);
	dat[k]=dat[2*k+1]+dat[2*k+2];
}
void modify(int l,int r,int p,int k,int x){
	if(r-l==1){
		dat[k].update(l,x);
		return;
	}
	int mid=(l+r)>>1;
	if(p<mid)modify(l,mid,p,2*k+1,x);
	else modify(mid,r,p,2*k+2,x);
	dat[k]=dat[2*k+1]+dat[2*k+2];
}
D qry(int l,int r,int x,int y,int k){
	if(l>=y||x>=r)return D();
	if(x<=l&&r<=y)return dat[k];
	int mid=(l+r)>>1;
	return qry(l,mid,x,y,2*k+1)+qry(mid,r,x,y,2*k+2);
}
int main(){
	n=getint();q=getint();m=getint();
	rep(i,n)a[i]=getint();
	build(0,n,0);
	rep(qqq,q){
		int op=getint(),x=getint()-1,y=getint();
		if(op==1)modify(0,n,x,0,y);
		else printf("%lld\n",qry(0,n,x,y,0).res);
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

struct data {
    int l, r, x;
    data(int l, int r, int x) : l(l), r(r), x(x) { }
};

ostream &operator<<(ostream &out, const data &d)
{
    return out << "(" << d.l << "," << d.r << "," << d.x << ")";
}
ostream &operator<<(ostream &out, const vector<data> &vd)
{
    out << "{";
    for (data d : vd) out << d;
    out << "}";
    return out;
}

const int MAXN = 100007;

int a[MAXN];
int x;

vector<data>bam[4*MAXN], dan[4*MAXN];
LL tr[4*MAXN];

vector<data> bamCombine(const vector<data> &b1, const vector<data> &b2)
{
    if (b1.empty()) return b2;
    if (b2.empty()) return b1;
    vector<data>rt(b1);
    int last = rt.back().x;
    for (data d : b2) {
        d.x |= last;
        if (d.x != last) rt.push_back(d);
        else rt.back().r = d.r;
        last = d.x;
    }
    return rt;
}

vector<data> danCombine(const vector<data> &b1, const vector<data> &b2)
{
    if (b1.empty()) return b2;
    if (b2.empty()) return b1;

    vector<data>rt(b2);
    int last = rt.back().x;
    for (data d : b1) {
        d.x |= last;
        if (d.x != last) rt.push_back(d);
        else rt.back().l = d.l;
        last = d.x;
    }
    return rt;
}

LL calculate(vector<data>L, vector<data>R)
{
    if (L.empty()||R.empty()) return 0;
    if ((L.back().x|R.back().x) < x) return 0;
    int r = R.back().r;
    LL ans = 0;
    int j = R.size()-1;
    for (data dl : L) {
        while (j > 0 && (R[j-1].x|dl.x) >= x) j--;
        if ((R[j].x|dl.x) >= x) ans += 1LL*(dl.r-dl.l+1)*(r-R[j].l+1);
    }

//    cout << ans << " for " << L << " " << R << endl;

    return ans;
}

void init(int u, int l, int r)
{
    if (l==r) {
        bam[u].emplace_back(l, r, a[l]);
        dan[u].emplace_back(l, r, a[l]);
        tr[u] = a[l] >= x;
        return;
    }

    int mid = (l+r)/2;
    init(u*2, l, mid);
    init(u*2+1, mid+1, r);
    bam[u] = bamCombine(bam[u*2], bam[u*2+1]);
    dan[u] = danCombine(dan[u*2], dan[u*2+1]);
    tr[u] = tr[u*2]+tr[u*2+1]+calculate(dan[u*2], bam[u*2+1]);
//    cout << bam[u] << " " << dan[u] << endl;
//    cout << "tr[" << l << "," << r << "] = " << tr[u] << endl;
}

void update(int u, int l, int r, int idx, int y)
{
    if (l==r) {
        bam[u].clear(); dan[u].clear();
        a[l] = y;
        bam[u].emplace_back(l, r, a[l]);
        dan[u].emplace_back(l, r, a[l]);
        tr[u] = a[l] >= x;
        return;
    }

    int mid = (l+r)/2;
    if (idx <= mid) update(u*2, l, mid, idx, y);
    else update(u*2+1, mid+1, r, idx, y);
    bam[u] = bamCombine(bam[u*2], bam[u*2+1]);
    dan[u] = danCombine(dan[u*2], dan[u*2+1]);
    tr[u] = tr[u*2]+tr[u*2+1]+calculate(dan[u*2], bam[u*2+1]);
//    cout << "tr[" << l << "," << r << "] = " << tr[u] << endl;
}

vector<data>qbam[4*MAXN], qdan[4*MAXN];

LL query(int u, int l, int r, int x, int y)
{
    qbam[u].clear();
    qdan[u].clear();
    if (r < x || y < l) return 0;
    if (x <= l && r <= y) {
        qbam[u] = bam[u];
        qdan[u] = dan[u];
        return tr[u];
    }
    int mid = (l+r)/2;
    LL ans = query(u*2, l, mid, x, y)+query(u*2+1, mid+1, r, x, y);
    ans += calculate(qdan[u*2], qbam[u*2+1]);
    qbam[u] = bamCombine(qbam[u*2], qbam[u*2+1]);
    qdan[u] = danCombine(qdan[u*2], qdan[u*2+1]);
    return ans;
}

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

    int n, m;
    cin >> n >> m >> x;

    for (int i = 1; i <= n; i++) cin >> a[i];

    init(1, 1, n);
    while (m--) {
        int op, l, r;
        cin >> op >> l >> r;
        if (op==1) update(1, 1, n, l, r);
        else cout << query(1, 1, n, l, r) << "\n";
    }

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

struct datum {
    int l, r, x;
    datum(int l, int r, int x) : l(l), r(r), x(x) { }
};

ostream &operator<<(ostream &out, const datum &d)
{
    return out << "(" << d.l << "," << d.r << "," << d.x << ")";
}
ostream &operator<<(ostream &out, const vector<datum> &vd)
{
    out << "{";
    for (datum d : vd) out << d;
    out << "}";
    return out;
}

const int MAXN = 100007;

int a[MAXN];
int x;

vector<datum>bam[4*MAXN], dan[4*MAXN];
LL tr[4*MAXN];

vector<datum> bamCombine(const vector<datum> &b1, const vector<datum> &b2)
{
    if (b1.empty()) return b2;
    if (b2.empty()) return b1;
    vector<datum>rt(b1);
    int last = rt.back().x;
    for (datum d : b2) {
        d.x |= last;
        if (d.x != last) rt.push_back(d);
        else rt.back().r = d.r;
        last = d.x;
    }
    return rt;
}

vector<datum> danCombine(const vector<datum> &b1, const vector<datum> &b2)
{
    if (b1.empty()) return b2;
    if (b2.empty()) return b1;

    vector<datum>rt(b2);
    int last = rt.back().x;
    for (datum d : b1) {
        d.x |= last;
        if (d.x != last) rt.push_back(d);
        else rt.back().l = d.l;
        last = d.x;
    }
    return rt;
}

LL calculate(vector<datum>L, vector<datum>R)
{
    if (L.empty()||R.empty()) return 0;
    if ((L.back().x|R.back().x) < x) return 0;
    int r = R.back().r;
    LL ans = 0;
    int j = R.size()-1;
    for (datum dl : L) {
        while (j > 0 && (R[j-1].x|dl.x) >= x) j--;
        if ((R[j].x|dl.x) >= x) ans += 1LL*(dl.r-dl.l+1)*(r-R[j].l+1);
    }

//    cout << ans << " for " << L << " " << R << endl;

    return ans;
}

void init(int u, int l, int r)
{
    if (l==r) {
        bam[u].emplace_back(l, r, a[l]);
        dan[u].emplace_back(l, r, a[l]);
        tr[u] = a[l] >= x;
        return;
    }

    int mid = (l+r)/2;
    init(u*2, l, mid);
    init(u*2+1, mid+1, r);
    bam[u] = bamCombine(bam[u*2], bam[u*2+1]);
    dan[u] = danCombine(dan[u*2], dan[u*2+1]);
    tr[u] = tr[u*2]+tr[u*2+1]+calculate(dan[u*2], bam[u*2+1]);
//    cout << bam[u] << " " << dan[u] << endl;
//    cout << "tr[" << l << "," << r << "] = " << tr[u] << endl;
}

void update(int u, int l, int r, int idx, int y)
{
    if (l==r) {
        bam[u].clear(); dan[u].clear();
        a[l] = y;
        bam[u].emplace_back(l, r, a[l]);
        dan[u].emplace_back(l, r, a[l]);
        tr[u] = a[l] >= x;
        return;
    }

    int mid = (l+r)/2;
    if (idx <= mid) update(u*2, l, mid, idx, y);
    else update(u*2+1, mid+1, r, idx, y);
    bam[u] = bamCombine(bam[u*2], bam[u*2+1]);
    dan[u] = danCombine(dan[u*2], dan[u*2+1]);
    tr[u] = tr[u*2]+tr[u*2+1]+calculate(dan[u*2], bam[u*2+1]);
//    cout << "tr[" << l << "," << r << "] = " << tr[u] << endl;
}

vector<datum>qbam[4*MAXN], qdan[4*MAXN];

LL query(int u, int l, int r, int x, int y)
{
    qbam[u].clear();
    qdan[u].clear();
    if (r < x || y < l) return 0;
    if (x <= l && r <= y) {
        qbam[u] = bam[u];
        qdan[u] = dan[u];
        return tr[u];
    }
    int mid = (l+r)/2;
    LL ans = query(u*2, l, mid, x, y)+query(u*2+1, mid+1, r, x, y);
    ans += calculate(qdan[u*2], qbam[u*2+1]);
    qbam[u] = bamCombine(qbam[u*2], qbam[u*2+1]);
    qdan[u] = danCombine(qdan[u*2], qdan[u*2+1]);
    return ans;
}

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

    int n, m;
    cin >> n >> m >> x;

    for (int i = 1; i <= n; i++) cin >> a[i];

    init(1, 1, n);
    while (m--) {
        int op, l, r;
        cin >> op >> l >> r;
        if (op==1) update(1, 1, n, l, r);
        else cout << query(1, 1, n, l, r) << "\n";
    }

    return 0;
}


#include <bits/stdc++.h>
using namespace std;

#pragma GCC optimize("O2,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("Os")

#define F first
#define S second
#define pb push_back
#define SZ(x) (ll)(x.size())
#define all(x) x.begin(),x.end()
#define MP make_pair

typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pll;

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

const ll maxn=1e5+10, maxm=5e2+10, lg=21, mod=1e9+7, inf=1e18;

#define lc (v<<1)
#define rc (lc^1)
#define md ((s+t)>>1)

ll n,q,X;

struct node{ll c=0;vector<pll> P,S;}seg[maxn<<2];
node mrg(node l,node r){
	if(l.P.empty()) return r;
	if(r.P.empty()) return l;
	node ret; ret.c=l.c+r.c;
	ll le=SZ(l.S)-1,cc=0;
	for(auto x:r.P){
		while(le>=0 && (x.F|l.S[le].F)>=X) cc+=l.S[le--].S;
		ret.c+=cc*x.S;
	}
	ret.P=l.P;
	for(auto x:r.P){
		if((ret.P.back().F&x.F)!=x.F) ret.P.pb({ret.P.back().F|x.F,0});
		ret.P.back().S+=x.S;
	}
	ret.S=r.S;
	for(auto x:l.S){
		if((ret.S.back().F&x.F)!=x.F) ret.S.pb({ret.S.back().F|x.F,0});
		ret.S.back().S+=x.S;
	}
	return ret;
}
void goz(ll id,ll x,ll s=0,ll t=n,ll v=1){
	if(t-s==1){
		seg[v].P=seg[v].S={{x,1}};
		seg[v].c=(x>=X);
		return;
	}
	(id<md ? goz(id,x,s,md,lc):goz(id,x,md,t,rc));
	seg[v]=mrg(seg[lc],seg[rc]);
}
node get(ll l,ll r,ll s=0,ll t=n,ll v=1){
	if(l>=t || r<=s) return node();
	if(l<=s && r>=t) return seg[v];
	return mrg(get(l,r,s,md,lc),get(l,r,md,t,rc));
}

int main(){
	ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);

	cin>>n>>q>>X;
	for(int i=0,x;i<n;i++) cin>>x, goz(i,x);
	while(q--){
		ll ty,l,r; cin>>ty>>l>>r;
		if(ty==1) goz(--l,r);
		else cout<<get(--l,r).c<<'\n';
	}

	return 0;
}


#include "omp.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <vector>
#include <cassert>
#include <fstream>
#include <algorithm>
#include <list>
#include <random>
#include <ctime>
#include <random>
#include <bitset>
#include <unordered_set>
#include <cassert>
#include <list>

using namespace std;

typedef long long ll;
typedef long double ld;

const int sze = 1 << 17, psze = 20;

struct node
{
	node *left, *right;
	int y, cnt, v, upd;
	ll sm;

	node(int v) : left(0), right(0), y((rand() << 16) ^ rand()), cnt(1), v(v), sm(v), upd(-1) {};
};

typedef node* treap;
typedef pair<treap, treap> ptt;

int tree[sze << 1];

void push(treap cur)
{
	if (!cur || cur->upd == -1)
		return;

	if (cur->left)
		cur->left->upd = cur->upd;

	if (cur->right)
		cur->right->upd = cur->upd;

	cur->v = cur->upd;
	cur->sm = ll(cur->cnt) * cur->upd;
	cur->upd = -1;
}

int get(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->cnt;
}

ll get_sm(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->sm;
}

treap update(treap cur)
{
	push(cur);
	cur->cnt = 1 + get(cur->left) + get(cur->right);
	cur->sm = get_sm(cur->left) + get_sm(cur->right) + cur->v;
	return cur;
}

treap merge(treap L, treap R)
{
	push(L);
	push(R);

	if (!L)
		return R;

	if (!R)
		return L;

	if (L->y > R->y)
	{
		L->right = merge(L->right, R);
		return update(L);
	}
	else
	{
		R->left = merge(L, R->left);
		return update(R);
	}
}

ptt split(treap cur, int x)
{
	push(cur);

	if (!cur)
		return { cur, cur };

	int cur_x = get(cur->left);

	if (cur_x <= x)
	{
		ptt ans = split(cur->right, x - cur_x - 1);
		cur->right = ans.first;

		return { update(cur), ans.second };
	}
	else
	{
		ptt ans = split(cur->left, x);
		cur->left = ans.second;

		return { ans.first, update(cur) };
	}
}

int count(int v)
{
	int cnt = 0;
	for (int i = 0; i < psze; ++i)
		if (v & (1 << i))
			cnt++;

	return cnt;
}

int get(int l, int r, int lb, int rb, int ind)
{
	assert(l >= 1);
	assert(r >= 1);

	if (l == lb && r == rb)
		return tree[ind];

	int m = (lb + rb) >> 1;
	int first = 0, second = 0;

	if (l <= m)
		first = get(l, min(m, r), lb, m, ind << 1);

	if (r > m)
		second = get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

	return first | second;
}

void update(int ind, int v)
{
	ind += sze;
	tree[ind] = v;
	ind >>= 1;

	while (ind)
	{
		tree[ind] = tree[ind << 1] | tree[ind << 1 | 1];
		ind >>= 1;
	}
}

int get_bit(int l, int r)
{
	int cnt = get(l + 1, r + 1, 1, sze, 1);
	return cnt;
}

int n, q, x;
int cur = 0, pos = 0;

void get_left(int l, int r, int lb, int rb, int ind)
{
	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((cur | tree[ind]) < x)
		{
			cur |= tree[ind];
			return;
		}

		if (lb == rb)
		{
			pos = lb;
			return;
		}

		if ((cur | tree[ind << 1]) >= x)
			get_left(l, m, l, m, ind << 1);
		else
		{
			cur |= tree[ind << 1];
			get_left(m + 1, r, m + 1, r, ind << 1 | 1);
		}
	}

	if (l <= m && !pos)
		get_left(l, min(m, r), lb, m, ind << 1);

	if (r > m && !pos)
		get_left(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

}

int find(int i)
{
	cur = 0, pos = 0;
	get_left(i + 1, n, 1, sze, 1);

	int ans = !pos ? n : pos - 1;
	return ans;
}

char counting[1 << 20];

int get_get(int l, int r, int lb, int rb, int ind, int v)
{
	assert(l >= 1);
	assert(r >= 1);

	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((tree[ind] | v) == v)
			return -1;

		if (lb == rb)
			return lb - 1;

		if ((tree[ind << 1 | 1] | v) != v)
			return get_get(m + 1, rb, m + 1, rb, ind << 1 | 1, v);
		else
			return get_get(lb, m, lb, m, ind << 1, v);
	}

	int first = -1, second = -1;

	if (r > m && (tree[ind << 1 | 1] | v) != v)
		second = get_get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, v);

	if (second == -1 && l <= m && (tree[ind << 1] | v) != v)
		first = get_get(l, min(m, r), lb, m, ind << 1, v);

	return max(first, second);
}

int find_pos(int l, int r, int v)
{
	return get_get(l, r, 1, sze, 1, v);
}

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

	srand(time(0));
	for (int i = 0; i < (1 << 20); ++i)
		counting[i] = count(i);

	cin >> n >> q >> x;
	vector<int> values(n);

	treap root = 0;

	for (int i = 0; i < n; ++i)
		cin >> values[i];

	for (int i = 0; i < n; ++i)
		tree[i + sze] = values[i];

	for (int i = sze - 1; i; --i)
		tree[i] = tree[i << 1] | tree[i << 1 | 1];

	for (int i = 0; i < n; ++i)
	{
		if (values[i] >= x)
			root = merge(root, new node(i));
		else
			root = merge(root, new node(find(i)));
	}

	for (int i = 0; i < q; ++i)
	{
		int label;
		cin >> label;

		if (label == 1)
		{
			int ind, v;
			cin >> ind >> v;
			ind--;

			update(ind, v);
			int prev = ind;
			int ccccc = 0;

			while (prev >= 0 && v < x)
			{
				ccccc++;
				int l = find_pos(1, prev + 1, v);
				int r = l + 1;

				ptt F1 = split(root, prev);
				ptt F2 = split(F1.first, r - 1);
				F2.second->upd = find(r);
				root = merge(merge(F2.first, F2.second), F1.second);

				prev = l;
				if (prev >= 0)
					v = get_bit(l, ind);

				assert(ccccc < 30);
			}

			if (prev >= 0)
			{
				ptt F1 = split(root, prev);

				int l = -1, r = F1.first->cnt;
				while (r - l > 1)
				{
					int m = (l + r) >> 1;

					ptt F11 = split(F1.first, m);
					ptt F22 = split(F11.first, m - 1);

					if (F22.second->v >= ind + 1)
						r = m;
					else
						l = m;

					F1.first = merge(merge(F22.first, F22.second), F11.second);
				}

				ptt F2 = split(F1.first, l);

				if (F2.second)
					F2.second->upd = ind;

				root = merge(merge(F2.first, F2.second), F1.second);
			}
		}
		else
		{
			int l, r;
			cin >> l >> r;
			l--, r--;

			ptt F1 = split(root, r);
			ptt F2 = split(F1.first, l - 1);

			int lb = -1, rb = F2.second->cnt;
			while (rb - lb > 1)
			{
				int m = (lb + rb) >> 1;
				ptt F11 = split(F2.second, m);
				ptt F22 = split(F11.first, m - 1);

				if (F22.second->v > r + 1)
					rb = m;
				else
					lb = m;

				F2.second = merge(merge(F22.first, F22.second), F11.second);
			}

			ptt F11 = split(F2.second, rb - 1);
			ll a = 0;
			ll b = 0;

			if (F11.first)
				a = F11.first->sm;

			if (F11.second)
				b = ll(F11.second->cnt) * (r + 1);

			ll c = ll(l + r) * (r - l + 1) / 2;
			ll d = ll(r - l + 1) * (r - l + 2) / 2;

			ll ans = d - (a + b - c);
			cout << ans << '\n';

			F2.second = merge(F11.first, F11.second);
			root = merge(merge(F2.first, F2.second), F1.second);
		}
	}

	return 0;
}


#include "omp.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <vector>
#include <cassert>
#include <fstream>
#include <algorithm>
#include <list>
#include <random>
#include <ctime>
#include <random>
#include <bitset>
#include <unordered_set>
#include <cassert>
#include <list>

using namespace std;

typedef long long ll;
typedef long double ld;

const int sze = 1 << 17, psze = 20;

struct node
{
	node *left, *right;
	int y, cnt, v, upd;
	ll sm;

	node(int v = 0) : left(0), right(0), y((rand() << 16) ^ rand()), cnt(1), v(v), sm(v), upd(-1) {};
};

typedef node* treap;
typedef pair<treap, treap> ptt;

int tree[sze << 1];

void push(treap cur)
{
	if (!cur || cur->upd == -1)
		return;

	if (cur->left)
		cur->left->upd = cur->upd;

	if (cur->right)
		cur->right->upd = cur->upd;

	cur->v = cur->upd;
	cur->sm = ll(cur->cnt) * cur->upd;
	cur->upd = -1;
}

int get(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->cnt;
}

ll get_sm(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->sm;
}

treap update(treap cur)
{
	push(cur);
	cur->cnt = 1 + get(cur->left) + get(cur->right);
	cur->sm = get_sm(cur->left) + get_sm(cur->right) + cur->v;
	return cur;
}

treap merge(treap L, treap R)
{
	push(L);
	push(R);

	if (!L)
		return R;

	if (!R)
		return L;

	if (L->y > R->y)
	{
		L->right = merge(L->right, R);
		return update(L);
	}
	else
	{
		R->left = merge(L, R->left);
		return update(R);
	}
}

ptt split(treap cur, int x)
{
	push(cur);

	if (!cur)
		return { cur, cur };

	int cur_x = get(cur->left);

	if (cur_x <= x)
	{
		ptt ans = split(cur->right, x - cur_x - 1);
		cur->right = ans.first;

		return { update(cur), ans.second };
	}
	else
	{
		ptt ans = split(cur->left, x);
		cur->left = ans.second;

		return { ans.first, update(cur) };
	}
}

int count(int v)
{
	int cnt = 0;
	for (int i = 0; i < psze; ++i)
		if (v & (1 << i))
			cnt++;

	return cnt;
}

int get(int l, int r, int lb, int rb, int ind)
{
	assert(l >= 1);
	assert(r >= 1);

	if (l == lb && r == rb)
		return tree[ind];

	int m = (lb + rb) >> 1;
	int first = 0, second = 0;

	if (l <= m)
		first = get(l, min(m, r), lb, m, ind << 1);

	if (r > m)
		second = get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

	return first | second;
}

void update(int ind, int v)
{
	ind += sze;
	tree[ind] = v;
	ind >>= 1;

	while (ind)
	{
		tree[ind] = tree[ind << 1] | tree[ind << 1 | 1];
		ind >>= 1;
	}
}

int get_bit(int l, int r)
{
	int cnt = get(l + 1, r + 1, 1, sze, 1);
	return cnt;
}

int n, q, x;

int find(int i)
{
	int l = i, r = n;

	while (r - l > 1)
	{
		int m = (l + r) >> 1;

		if (get_bit(i, m) >= x)
			r = m;
		else
			l = m;
	}

	return r;
}

char counting[1 << 20];

int get_get(int l, int r, int lb, int rb, int ind, int v)
{
	assert(l >= 1);
	assert(r >= 1);

	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((tree[ind] | v) == v)
			return -1;

		if (lb == rb)
			return lb - 1;

		if ((tree[ind << 1 | 1] | v) != v)
			return get_get(m + 1, rb, m + 1, rb, ind << 1 | 1, v);
		else
			return get_get(lb, m, lb, m, ind << 1, v);
	}

	int first = -1, second = -1;

	if (r > m && (tree[ind << 1 | 1] | v) != v)
		second = get_get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, v);

	if (second == -1 && l <= m && (tree[ind << 1] | v) != v)
		first = get_get(l, min(m, r), lb, m, ind << 1, v);

	return max(first, second);
}

int find_pos(int l, int r, int v)
{
	return get_get(l, r, 1, sze, 1, v);
}

node memory[sze];
int my_free = 0;

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

	srand(time(0));
	for (int i = 0; i < (1 << 20); ++i)
		counting[i] = count(i);

	cin >> n >> q >> x;
	vector<int> values(n);

	treap root = 0;

	for (int i = 0; i < n; ++i)
		cin >> values[i];

	for (int i = 0; i < n; ++i)
		tree[i + sze] = values[i];

	for (int i = sze - 1; i; --i)
		tree[i] = tree[i << 1] | tree[i << 1 | 1];

	for (int i = 0; i < n; ++i)
	{
		if (values[i] >= x)
		{
			memory[my_free] = i;
			root = merge(root, &memory[my_free]);
		}
		else
		{
			memory[my_free] = find(i);
			root = merge(root, &memory[my_free]);
		}

		my_free++;
	}

	for (int i = 0; i < q; ++i)
	{
		int label;
		cin >> label;

		if (label == 1)
		{
			int ind, v;
			cin >> ind >> v;
			ind--;

			update(ind, v);
			int prev = ind;

			while (prev >= 0 && v < x)
			{
				int l = find_pos(1, prev + 1, v);
				int r = l + 1;

				ptt F1 = split(root, prev);
				ptt F2 = split(F1.first, r - 1);
				F2.second->upd = find(r);
				root = merge(merge(F2.first, F2.second), F1.second);

				prev = l;
				if (prev >= 0)
					v = get_bit(l, ind);
			}

			if (prev >= 0)
			{
				ptt F1 = split(root, prev);

				int l = -1, r = F1.first->cnt;
				while (r - l > 1)
				{
					int m = (l + r) >> 1;

					ptt F11 = split(F1.first, m);
					ptt F22 = split(F11.first, m - 1);

					if (F22.second->v >= ind + 1)
						r = m;
					else
						l = m;

					F1.first = merge(merge(F22.first, F22.second), F11.second);
				}

				ptt F2 = split(F1.first, l);

				if (F2.second)
					F2.second->upd = ind;

				root = merge(merge(F2.first, F2.second), F1.second);
			}
		}
		else
		{
			int l, r;
			cin >> l >> r;
			l--, r--;

			ptt F1 = split(root, r);
			ptt F2 = split(F1.first, l - 1);

			int lb = -1, rb = F2.second->cnt;
			while (rb - lb > 1)
			{
				int m = (lb + rb) >> 1;
				ptt F11 = split(F2.second, m);
				ptt F22 = split(F11.first, m - 1);

				if (F22.second->v > r + 1)
					rb = m;
				else
					lb = m;

				F2.second = merge(merge(F22.first, F22.second), F11.second);
			}

			ptt F11 = split(F2.second, rb - 1);
			ll a = 0;
			ll b = 0;

			if (F11.first)
				a = F11.first->sm;

			if (F11.second)
				b = ll(F11.second->cnt) * (r + 1);

			ll c = ll(l + r) * (r - l + 1) / 2;
			ll d = ll(r - l + 1) * (r - l + 2) / 2;

			ll ans = d - (a + b - c);
			cout << ans << '\n';

			F2.second = merge(F11.first, F11.second);
			root = merge(merge(F2.first, F2.second), F1.second);
		}
	}

	return 0;
}


#include "omp.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <vector>
#include <cassert>
#include <fstream>
#include <algorithm>
#include <list>
#include <random>
#include <ctime>
#include <random>
#include <bitset>
#include <unordered_set>
#include <cassert>
#include <list>

using namespace std;

typedef long long ll;
typedef long double ld;

const int sze = 1 << 17, psze = 20;

struct node
{
	node *left, *right;
	int y, cnt, v, upd;
	ll sm;

	node(int v) : left(0), right(0), y((rand() << 16) ^ rand()), cnt(1), v(v), sm(v), upd(-1) {};
};

typedef node* treap;
typedef pair<treap, treap> ptt;

int tree[sze << 1];

void push(treap cur)
{
	if (!cur || cur->upd == -1)
		return;

	if (cur->left)
		cur->left->upd = cur->upd;

	if (cur->right)
		cur->right->upd = cur->upd;

	cur->v = cur->upd;
	cur->sm = ll(cur->cnt) * cur->upd;
	cur->upd = -1;
}

int get(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->cnt;
}

ll get_sm(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->sm;
}

treap update(treap cur)
{
	push(cur);
	cur->cnt = 1 + get(cur->left) + get(cur->right);
	cur->sm = get_sm(cur->left) + get_sm(cur->right) + cur->v;
	return cur;
}

treap merge(treap L, treap R)
{
	push(L);
	push(R);

	if (!L)
		return R;

	if (!R)
		return L;

	if (L->y > R->y)
	{
		L->right = merge(L->right, R);
		return update(L);
	}
	else
	{
		R->left = merge(L, R->left);
		return update(R);
	}
}

ptt split(treap cur, int x)
{
	push(cur);

	if (!cur)
		return { cur, cur };

	int cur_x = get(cur->left);

	if (cur_x <= x)
	{
		ptt ans = split(cur->right, x - cur_x - 1);
		cur->right = ans.first;

		return { update(cur), ans.second };
	}
	else
	{
		ptt ans = split(cur->left, x);
		cur->left = ans.second;

		return { ans.first, update(cur) };
	}
}

int count(int v)
{
	int cnt = 0;
	for (int i = 0; i < psze; ++i)
		if (v & (1 << i))
			cnt++;

	return cnt;
}

int get(int l, int r, int lb, int rb, int ind)
{
	assert(l >= 1);
	assert(r >= 1);

	if (l == lb && r == rb)
		return tree[ind];

	int m = (lb + rb) >> 1;
	int first = 0, second = 0;

	if (l <= m)
		first = get(l, min(m, r), lb, m, ind << 1);

	if (r > m)
		second = get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

	return first | second;
}

void update(int ind, int v)
{
	ind += sze;
	tree[ind] = v;
	ind >>= 1;

	while (ind)
	{
		tree[ind] = tree[ind << 1] | tree[ind << 1 | 1];
		ind >>= 1;
	}
}

int get_bit(int l, int r)
{
	int cnt = get(l + 1, r + 1, 1, sze, 1);
	return cnt;
}

int n, q, x;

int find(int i)
{
	int l = i, r = n;

	while (r - l > 1)
	{
		int m = (l + r) >> 1;

		if (get_bit(i, m) >= x)
			r = m;
		else
			l = m;
	}

	return r;
}

char counting[1 << 20];

int get_get(int l, int r, int lb, int rb, int ind, int v)
{
	assert(l >= 1);
	assert(r >= 1);

	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((tree[ind] | v) == v)
			return -1;

		if (lb == rb)
			return lb - 1;

		if ((tree[ind << 1 | 1] | v) != v)
			return get_get(m + 1, rb, m + 1, rb, ind << 1 | 1, v);
		else
			return get_get(lb, m, lb, m, ind << 1, v);
	}

	int first = -1, second = -1;

	if (r > m && (tree[ind << 1 | 1] | v) != v)
		second = get_get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, v);

	if (second == -1 && l <= m && (tree[ind << 1] | v) != v)
		first = get_get(l, min(m, r), lb, m, ind << 1, v);

	return max(first, second);
}

int find_pos(int l, int r, int v)
{
	return get_get(l, r, 1, sze, 1, v);
}

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

	srand(time(0));
	for (int i = 0; i < (1 << 20); ++i)
		counting[i] = count(i);

	cin >> n >> q >> x;
	vector<int> values(n);

	treap root = 0;

	for (int i = 0; i < n; ++i)
		cin >> values[i];

	for (int i = 0; i < n; ++i)
		tree[i + sze] = values[i];

	for (int i = sze - 1; i; --i)
		tree[i] = tree[i << 1] | tree[i << 1 | 1];

	for (int i = 0; i < n; ++i)
	{
		if (values[i] >= x)
			root = merge(root, new node(i));
		else
			root = merge(root, new node(find(i)));
	}

	for (int i = 0; i < q; ++i)
	{
		int label;
		cin >> label;

		if (label == 1)
		{
			int ind, v;
			cin >> ind >> v;
			ind--;

			update(ind, v);
			int prev = ind;

			while (prev >= 0 && v < x)
			{
				int l = find_pos(1, prev + 1, v);
				int r = l + 1;

				ptt F1 = split(root, prev);
				ptt F2 = split(F1.first, r - 1);
				F2.second->upd = find(r);
				root = merge(merge(F2.first, F2.second), F1.second);

				prev = l;
				if (prev >= 0)
					v = get_bit(l, ind);
			}

			if (prev >= 0)
			{
				ptt F1 = split(root, prev);

				int l = -1, r = F1.first->cnt;
				while (r - l > 1)
				{
					int m = (l + r) >> 1;

					ptt F11 = split(F1.first, m);
					ptt F22 = split(F11.first, m - 1);

					if (F22.second->v >= ind + 1)
						r = m;
					else
						l = m;

					F1.first = merge(merge(F22.first, F22.second), F11.second);
				}

				ptt F2 = split(F1.first, l);

				if (F2.second)
					F2.second->upd = ind;

				root = merge(merge(F2.first, F2.second), F1.second);
			}
		}
		else
		{
			int l, r;
			cin >> l >> r;
			l--, r--;

			ptt F1 = split(root, r);
			ptt F2 = split(F1.first, l - 1);

			int lb = -1, rb = F2.second->cnt;
			while (rb - lb > 1)
			{
				int m = (lb + rb) >> 1;
				ptt F11 = split(F2.second, m);
				ptt F22 = split(F11.first, m - 1);

				if (F22.second->v > r + 1)
					rb = m;
				else
					lb = m;

				F2.second = merge(merge(F22.first, F22.second), F11.second);
			}

			ptt F11 = split(F2.second, rb - 1);
			ll a = 0;
			ll b = 0;

			if (F11.first)
				a = F11.first->sm;

			if (F11.second)
				b = ll(F11.second->cnt) * (r + 1);

			ll c = ll(l + r) * (r - l + 1) / 2;
			ll d = ll(r - l + 1) * (r - l + 2) / 2;

			ll ans = d - (a + b - c);
			cout << ans << '\n';

			F2.second = merge(F11.first, F11.second);
			root = merge(merge(F2.first, F2.second), F1.second);
		}
	}

	return 0;
}


#include "omp.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <vector>
#include <cassert>
#include <fstream>
#include <algorithm>
#include <list>
#include <random>
#include <ctime>
#include <random>
#include <bitset>
#include <unordered_set>
#include <cassert>
#include <list>

using namespace std;

typedef long long ll;
typedef long double ld;

const int sze = 1 << 17, psze = 20;

int tree_or[sze << 1], updating[sze << 1];
ll tree[sze << 1];

int n, q, x;

int first_large(int l, int r, int lb, int rb, int ind, int &cur)
{
	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((tree_or[ind] | cur) < x)
		{
			cur |= tree_or[ind];
			return sze;
		}

		if (lb == rb)
		{
			cur |= tree_or[ind];
			return lb;
		}

		if ((cur | tree_or[ind << 1]) >= x)
			return first_large(l, m, l, m, ind << 1, cur);
		else
		{
			cur |= tree_or[ind << 1];
			return first_large(m + 1, r, m + 1, r, ind << 1 | 1, cur);
		}
	}

	int first = sze, second = sze;
	assert(cur < x);

	if (l <= m)
		first = first_large(l, min(m, r), lb, m, ind << 1, cur);

	if (r > m && cur < x)
		second = first_large(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, cur);

	if (first == sze)
		return second;

	if (second == sze)
		return first;

	return min(first, second);
}

void push(int ind, ll len)
{
	if (updating[ind] == -1)
		return;

	tree[ind] = len * updating[ind];

	if (len != 1)
		updating[ind << 1] = updating[ind << 1 | 1] = updating[ind];
}

ll get(int l, int r, int lb, int rb, int ind)
{
	push(ind, rb - lb + 1);

	if (l == lb && r == rb)
		return tree[ind];

	ll first = 0, second = 0;
	int m = (lb + rb) >> 1;

	if (l <= m)
		first = get(l, min(m, r), lb, m, ind << 1);

	if (r > m)
		second = get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

	push(ind << 1, rb - m);
	push(ind << 1 | 1, rb - m);
	tree[ind] = tree[ind << 1] + tree[ind << 1 | 1];

	return first + second;
}

void update_or(int ind, int v)
{
	ind += sze - 1;
	tree_or[ind] = v;
	ind >>= 1;

	while (ind)
	{
		tree_or[ind] = tree_or[ind << 1] | tree_or[ind << 1 | 1];
		ind >>= 1;
	}
}

int bits(int l, int r, int lb, int rb, int ind, int v)
{
	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((tree_or[ind] | v) == v)
			return 0;

		if (lb == rb)
			return lb;

		if ((tree_or[ind << 1 | 1] | v) != v)
			return bits(m + 1, r, m + 1, r, ind << 1 | 1, v);
		else
			return bits(l, m, l, m, ind << 1, v);
	}

	int first = 0, second = 0;

	if (r > m)
		second = bits(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, v);

	if (!second && l <= m)
		first = bits(l, min(m, r), lb, m, ind << 1, v);

	return max(first, second);
}

int get_or(int l, int r, int lb, int rb, int ind)
{
	if (l == lb && r == rb)
		return tree_or[ind];

	int first = 0, second = 0;
	int m = (lb + rb) >> 1;

	if (l <= m)
		first = get_or(l, min(m, r), lb, m, ind << 1);

	if (r > m)
		second = get_or(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

	return first | second;
}

void update(int l, int r, int lb, int rb, int ind, int v)
{
	push(ind, rb - lb + 1);

	if (l == lb && r == rb)
	{
		updating[ind] = v;
		push(ind, rb - lb + 1);
		return;
	}

	int m = (lb + rb) >> 1;

	if (l <= m)
		update(l, min(m, r), lb, m, ind << 1, v);

	if (r > m)
		update(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, v);

	push(ind << 1, rb - m);
	push(ind << 1 | 1, rb - m);
	tree[ind] = tree[ind << 1] + tree[ind << 1 | 1];
}

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

	cin >> n >> q >> x;

	vector<int> values(n);
	for (int i = 0; i < n; ++i)
		cin >> values[i];

	for (int i = 0; i < n; ++i)
		tree_or[i + sze] = values[i];

	for (int i = sze - 1; i; --i)
		tree_or[i] = tree_or[i << 1] | tree_or[i << 1 | 1];

	for (int i = 0; i < n; ++i)
	{
		if (values[i] >= x)
		{
			tree[i + sze] = i + 1;
			continue;
		}

		int c = 0;
		tree[i + sze] = first_large(i + 1, sze, 1, sze, 1, c);
	}

	for (int i = sze - 1; i; --i)
		tree[i] = tree[i << 1] + tree[i << 1 | 1];

	fill(updating, updating + (sze << 1), -1);

	for (int i = 0; i < q; ++i)
	{
		int label;
		cin >> label;

		if (label == 1)
		{
			int ind, v;
			cin >> ind >> v;
			update_or(ind, v);

			int prev = ind;
			while (prev && v < x)
			{
				int c = 0;
				int ind_new = bits(1, prev, 1, sze, 1, v);
				int pos = first_large(ind_new + 1, sze, 1, sze, 1, c);

				update(ind_new + 1, prev, 1, sze, 1, pos);

				if (ind_new)
					v = get_or(ind_new, ind, 1, sze, 1);

				prev = ind_new;
			}

			if (prev)
			{
				int l = 0, r = prev + 1;
				while (r - l > 1)
				{
					int m = (l + r) >> 1;

					if (get(m, m, 1, sze, 1) > ind)
						r = m;
					else
						l = m;
				}

				if (r != prev + 1)
					update(r, prev, 1, sze, 1, ind);
			}
		}
		else
		{
			int l, r;
			cin >> l >> r;

			int lb = l - 1, rb = r + 1;
			while (rb - lb > 1)
			{
				int m = (lb + rb) >> 1;

				if (get(m, m, 1, sze, 1) > r + 1)
					rb = m;
				else
					lb = m;
			}

			ll a = 0;

			if (lb != l - 1)
				a = get(l, lb, 1, sze, 1);

			ll b = ll(r + 1 - rb) * (r + 1);
			ll c = ll(l + r) * (r - l + 1) / 2;
			ll d = ll(r - l + 2) * (r - l + 1) / 2;

			cout << d - (a + b - c) << '\n';
		}
	}

	return 0;
}


#include "omp.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <vector>
#include <cassert>
#include <fstream>
#include <algorithm>
#include <list>
#include <random>
#include <ctime>
#include <random>
#include <bitset>
#include <unordered_set>
#include <cassert>
#include <list>

using namespace std;

typedef long long ll;
typedef long double ld;

const int sze = 1 << 17, psze = 20;

struct node
{
	node *left, *right;
	int y, cnt, v, upd;
	ll sm;

	node(int v) : left(0), right(0), y((rand() << 16) ^ rand()), cnt(1), v(v), sm(v), upd(-1) {};
};

typedef node* treap;
typedef pair<treap, treap> ptt;

int tree[sze << 1];

void push(treap cur)
{
	if (!cur || cur->upd == -1)
		return;

	if (cur->left)
		cur->left->upd = cur->upd;

	if (cur->right)
		cur->right->upd = cur->upd;

	cur->v = cur->upd;
	cur->sm = ll(cur->cnt) * cur->upd;
	cur->upd = -1;
}

int get(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->cnt;
}

ll get_sm(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->sm;
}

treap update(treap cur)
{
	push(cur);
	cur->cnt = 1 + get(cur->left) + get(cur->right);
	cur->sm = get_sm(cur->left) + get_sm(cur->right) + cur->v;
	return cur;
}

treap merge(treap L, treap R)
{
	push(L);
	push(R);

	if (!L)
		return R;

	if (!R)
		return L;

	if (L->y > R->y)
	{
		L->right = merge(L->right, R);
		return update(L);
	}
	else
	{
		R->left = merge(L, R->left);
		return update(R);
	}
}

ptt split(treap cur, int x)
{
	push(cur);

	if (!cur)
		return { cur, cur };

	int cur_x = get(cur->left);

	if (cur_x <= x)
	{
		ptt ans = split(cur->right, x - cur_x - 1);
		cur->right = ans.first;

		return { update(cur), ans.second };
	}
	else
	{
		ptt ans = split(cur->left, x);
		cur->left = ans.second;

		return { ans.first, update(cur) };
	}
}

int count(int v)
{
	int cnt = 0;
	for (int i = 0; i < psze; ++i)
		if (v & (1 << i))
			cnt++;

	return cnt;
}

int get(int l, int r, int lb, int rb, int ind)
{
	assert(l >= 1);
	assert(r >= 1);

	if (l == lb && r == rb)
		return tree[ind];

	int m = (lb + rb) >> 1;
	int first = 0, second = 0;

	if (l <= m)
		first = get(l, min(m, r), lb, m, ind << 1);

	if (r > m)
		second = get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

	return first | second;
}

void update(int ind, int v)
{
	ind += sze;
	tree[ind] = v;
	ind >>= 1;

	while (ind)
	{
		tree[ind] = tree[ind << 1] | tree[ind << 1 | 1];
		ind >>= 1;
	}
}

int get_bit(int l, int r)
{
	int cnt = get(l + 1, r + 1, 1, sze, 1);
	return cnt;
}

int n, q, x;

int find(int i)
{
	int l = i, r = n;

	while (r - l > 1)
	{
		int m = (l + r) >> 1;

		if (get_bit(i, m) >= x)
			r = m;
		else
			l = m;
	}

	return r;
}

char counting[1 << 20];

int get_get(int l, int r, int lb, int rb, int ind, int v)
{
	assert(l >= 1);
	assert(r >= 1);

	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((tree[ind] | v) == v)
			return -1;

		if (lb == rb)
			return lb - 1;

		if ((tree[ind << 1 | 1] | v) != v)
			return get_get(m + 1, rb, m + 1, rb, ind << 1 | 1, v);
		else
			return get_get(lb, m, lb, m, ind << 1, v);
	}

	int first = -1, second = -1;

	if (r > m && (tree[ind << 1 | 1] | v) != v)
		second = get_get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, v);

	if (second == -1 && l <= m && (tree[ind << 1] | v) != v)
		first = get_get(l, min(m, r), lb, m, ind << 1, v);

	return max(first, second);
}

int find_pos(int l, int r, int v)
{
	return get_get(l, r, 1, sze, 1, v);
}

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

	srand(time(0));
	for (int i = 0; i < (1 << 20); ++i)
		counting[i] = count(i);

	cin >> n >> q >> x;
	vector<int> values(n);

	treap root = 0;

	for (int i = 0; i < n; ++i)
		cin >> values[i];

	for (int i = 0; i < n; ++i)
		tree[i + sze] = values[i];

	for (int i = sze - 1; i; --i)
		tree[i] = tree[i << 1] | tree[i << 1 | 1];

	for (int i = 0; i < n; ++i)
	{
		if (values[i] >= x)
			root = merge(root, new node(i));
		else
			root = merge(root, new node(find(i)));
	}

	for (int i = 0; i < q; ++i)
	{
		int label;
		cin >> label;

		if (label == 1)
		{
			int ind, v;
			cin >> ind >> v;
			ind--;

			update(ind, v);
			int prev = ind;
			int ccccc = 0;

			while (prev >= 0 && v < x)
			{
				ccccc++;
				int l = find_pos(1, prev + 1, v);
				int r = l + 1;

				ptt F1 = split(root, prev);
				ptt F2 = split(F1.first, r - 1);
				F2.second->upd = find(r);
				root = merge(merge(F2.first, F2.second), F1.second);

				prev = l;
				if (prev >= 0)
					v = get_bit(l, ind);

				assert(ccccc < 30);
			}

			if (prev >= 0)
			{
				ptt F1 = split(root, prev);

				int l = -1, r = F1.first->cnt;
				while (r - l > 1)
				{
					int m = (l + r) >> 1;

					ptt F11 = split(F1.first, m);
					ptt F22 = split(F11.first, m - 1);

					if (F22.second->v >= ind + 1)
						r = m;
					else
						l = m;

					F1.first = merge(merge(F22.first, F22.second), F11.second);
				}

				ptt F2 = split(F1.first, l);

				if (F2.second)
					F2.second->upd = ind;

				root = merge(merge(F2.first, F2.second), F1.second);
			}
		}
		else
		{
			int l, r;
			cin >> l >> r;
			l--, r--;

			ptt F1 = split(root, r);
			ptt F2 = split(F1.first, l - 1);

			int lb = -1, rb = F2.second->cnt;
			while (rb - lb > 1)
			{
				int m = (lb + rb) >> 1;
				ptt F11 = split(F2.second, m);
				ptt F22 = split(F11.first, m - 1);

				if (F22.second->v > r + 1)
					rb = m;
				else
					lb = m;

				F2.second = merge(merge(F22.first, F22.second), F11.second);
			}

			ptt F11 = split(F2.second, rb - 1);
			ll a = 0;
			ll b = 0;

			if (F11.first)
				a = F11.first->sm;

			if (F11.second)
				b = ll(F11.second->cnt) * (r + 1);

			ll c = ll(l + r) * (r - l + 1) / 2;
			ll d = ll(r - l + 1) * (r - l + 2) / 2;

			ll ans = d - (a + b - c);
			cout << ans << '\n';

			F2.second = merge(F11.first, F11.second);
			root = merge(merge(F2.first, F2.second), F1.second);
		}
	}

	return 0;
}


#include "omp.h"
#include <iostream>
#include <iomanip>
#include <string>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <vector>
#include <cassert>
#include <fstream>
#include <algorithm>
#include <list>
#include <random>
#include <ctime>
#include <random>
#include <bitset>
#include <unordered_set>
#include <cassert>
#include <list>

using namespace std;

typedef long long ll;
typedef long double ld;

const int sze = 1 << 17, psze = 20;

struct node
{
	node *left, *right;
	int y, cnt, v, upd;
	ll sm;

	node(int v) : left(0), right(0), y((rand() << 16) ^ rand()), cnt(1), v(v), sm(v), upd(-1) {};
};

typedef node* treap;
typedef pair<treap, treap> ptt;

int tree[sze << 1];

void push(treap cur)
{
	if (!cur || cur->upd == -1)
		return;

	if (cur->left)
		cur->left->upd = cur->upd;

	if (cur->right)
		cur->right->upd = cur->upd;

	cur->v = cur->upd;
	cur->sm = ll(cur->cnt) * cur->upd;
	cur->upd = -1;
}

int get(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->cnt;
}

ll get_sm(treap cur)
{
	push(cur);
	return !cur ? 0 : cur->sm;
}

treap update(treap cur)
{
	push(cur);
	cur->cnt = 1 + get(cur->left) + get(cur->right);
	cur->sm = get_sm(cur->left) + get_sm(cur->right) + cur->v;
	return cur;
}

treap merge(treap L, treap R)
{
	push(L);
	push(R);

	if (!L)
		return R;

	if (!R)
		return L;

	if (L->y > R->y)
	{
		L->right = merge(L->right, R);
		return update(L);
	}
	else
	{
		R->left = merge(L, R->left);
		return update(R);
	}
}

ptt split(treap cur, int x)
{
	push(cur);

	if (!cur)
		return { cur, cur };

	int cur_x = get(cur->left);

	if (cur_x <= x)
	{
		ptt ans = split(cur->right, x - cur_x - 1);
		cur->right = ans.first;

		return { update(cur), ans.second };
	}
	else
	{
		ptt ans = split(cur->left, x);
		cur->left = ans.second;

		return { ans.first, update(cur) };
	}
}

int count(int v)
{
	int cnt = 0;
	for (int i = 0; i < psze; ++i)
		if (v & (1 << i))
			cnt++;

	return cnt;
}

int get(int l, int r, int lb, int rb, int ind)
{
	if (l == lb && r == rb)
		return tree[ind];

	int m = (lb + rb) >> 1;
	int first = 0, second = 0;

	if (l <= m)
		first = get(l, min(m, r), lb, m, ind << 1);

	if (r > m)
		second = get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1);

	return first | second;
}

void update(int ind, int v)
{
	ind += sze;
	tree[ind] = v;
	ind >>= 1;

	while (ind)
	{
		tree[ind] = tree[ind << 1] | tree[ind << 1 | 1];
		ind >>= 1;
	}
}

int get_bit(int l, int r)
{
	int cnt = get(l + 1, r + 1, 1, sze, 1);
	return cnt;
}

int n, q, x;

int find(int i)
{
	int l = i, r = n;

	while (r - l > 1)
	{
		int m = (l + r) >> 1;

		if (get_bit(i, m) >= x)
			r = m;
		else
			l = m;
	}

	return r;
}

char counting[1 << 20];

int get_get(int l, int r, int lb, int rb, int ind, int v)
{

	int m = (lb + rb) >> 1;

	if (l == lb && r == rb)
	{
		if ((tree[ind] | v) == v)
			return -1;

		if (lb == rb)
			return lb - 1;

		if ((tree[ind << 1 | 1] | v) != v)
			return get_get(m + 1, rb, m + 1, rb, ind << 1 | 1, v);
		else
			return get_get(lb, m, lb, m, ind << 1, v);
	}

	int first = -1, second = -1;

	if (l <= m)
		first = get_get(l, min(m, r), lb, m, ind << 1, v);

	if (r > m)
		second = get_get(max(l, m + 1), r, m + 1, rb, ind << 1 | 1, v);

	return max(first, second);
}

int find_pos(int l, int r, int v)
{
	return get_get(l, r, 1, sze, 1, v);
}

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

	for (int i = 0; i < (1 << 20); ++i)
		counting[i] = count(i);

	cin >> n >> q >> x;
	vector<int> values(n);

	treap root = 0;

	for (int i = 0; i < n; ++i)
		cin >> values[i];

	for (int i = 0; i < n; ++i)
		tree[i + sze] = values[i];

	for (int i = sze - 1; i; --i)
		tree[i] = tree[i << 1] | tree[i << 1 | 1];

	for (int i = 0; i < n; ++i)
	{
		if (values[i] >= x)
			root = merge(root, new node(i));
		else
			root = merge(root, new node(find(i)));
	}

	for (int i = 0; i < q; ++i)
	{
		int label;
		cin >> label;

		if (label == 1)
		{
			int ind, v;
			cin >> ind >> v;
			ind--;

			update(ind, v);
			int prev = ind;

			while (prev >= 0 && v < x)
			{
				int l = find_pos(1, prev + 1, v);
				int r = l + 1;

				ptt F1 = split(root, prev);
				ptt F2 = split(F1.first, r - 1);
				F2.second->upd = find(r);
				root = merge(merge(F2.first, F2.second), F1.second);

				prev = l;
				if (prev >= 0)
					v = get_bit(l, ind);
			}

			if (prev >= 0)
			{
				ptt F1 = split(root, prev);

				int l = -1, r = F1.first->cnt;
				while (r - l > 1)
				{
					int m = (l + r) >> 1;

					ptt F11 = split(F1.first, m);
					ptt F22 = split(F11.first, m - 1);

					if (F22.second->v >= ind + 1)
						r = m;
					else
						l = m;

					F1.first = merge(merge(F22.first, F22.second), F11.second);
				}

				ptt F2 = split(F1.first, l);

				if (F2.second)
					F2.second->upd = ind;

				root = merge(merge(F2.first, F2.second), F1.second);
			}
		}
		else
		{
			int l, r;
			cin >> l >> r;
			l--, r--;

			ptt F1 = split(root, r);
			ptt F2 = split(F1.first, l - 1);

			int lb = -1, rb = F2.second->cnt;
			while (rb - lb > 1)
			{
				int m = (lb + rb) >> 1;
				ptt F11 = split(F2.second, m);
				ptt F22 = split(F11.first, m - 1);

				if (F22.second->v > r + 1)
					rb = m;
				else
					lb = m;

				F2.second = merge(merge(F22.first, F22.second), F11.second);
			}

			ptt F11 = split(F2.second, rb - 1);
			ll a = 0;
			ll b = 0;

			if (F11.first)
				a = F11.first->sm;

			if (F11.second)
				b = ll(F11.second->cnt) * (r + 1);

			ll c = ll(l + r) * (r - l + 1) / 2;
			ll d = ll(r - l + 1) * (r - l + 2) / 2;

			ll ans = d - (a + b - c);
			cout << ans << '\n';

			F2.second = merge(F11.first, F11.second);
			root = merge(merge(F2.first, F2.second), F1.second);
		}
	}

	return 0;
}