<p>There are some red and blue tiles arranged circularly. You are given an array of integers <code>colors</code> and a 2D integers array <code>queries</code>.</p>

<p>The color of tile <code>i</code> is represented by <code>colors[i]</code>:</p>

<ul>
	<li><code>colors[i] == 0</code> means that tile <code>i</code> is <strong>red</strong>.</li>
	<li><code>colors[i] == 1</code> means that tile <code>i</code> is <strong>blue</strong>.</li>
</ul>

<p>An <strong>alternating</strong> group is a contiguous subset of tiles in the circle with <strong>alternating</strong> colors (each tile in the group except the first and last one has a different color from its <b>adjacent</b> tiles in the group).</p>

<p>You have to process queries of two types:</p>

<ul>
	<li><code>queries[i] = [1, size<sub>i</sub>]</code>, determine the count of <strong>alternating</strong> groups with size <code>size<sub>i</sub></code>.</li>
	<li><code>queries[i] = [2, index<sub>i</sub>, color<sub>i</sub>]</code>, change <code>colors[index<sub>i</sub>]</code> to <code>color<font face="monospace"><sub>i</sub></font></code>.</li>
</ul>

<p>Return an array <code>answer</code> containing the results of the queries of the first type <em>in order</em>.</p>

<p><strong>Note</strong> that since <code>colors</code> represents a <strong>circle</strong>, the <strong>first</strong> and the <strong>last</strong> tiles are considered to be next to each other.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">colors = [0,1,1,0,1], queries = [[2,1,0],[1,4]]</span></p>

<p><strong>Output:</strong> <span class="example-io">[2]</span></p>

<p><strong>Explanation:</strong></p>

<p><strong class="example"><img alt="" data-darkreader-inline-bgcolor="" data-darkreader-inline-bgimage="" src="https://assets.leetcode.com/uploads/2024/06/03/screenshot-from-2024-06-03-20-14-44.png" style="width: 150px; height: 150px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem; --darkreader-inline-bgimage: initial; --darkreader-inline-bgcolor: #181a1b;" /></strong></p>

<p>First query:</p>

<p>Change <code>colors[1]</code> to 0.</p>

<p><img alt="" data-darkreader-inline-bgcolor="" data-darkreader-inline-bgimage="" src="https://assets.leetcode.com/uploads/2024/06/03/screenshot-from-2024-06-03-20-20-25.png" style="width: 150px; height: 150px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem; --darkreader-inline-bgimage: initial; --darkreader-inline-bgcolor: #181a1b;" /></p>

<p>Second query:</p>

<p>Count of the alternating groups with size 4:</p>

<p><img alt="" data-darkreader-inline-bgcolor="" data-darkreader-inline-bgimage="" src="https://assets.leetcode.com/uploads/2024/06/03/screenshot-from-2024-06-03-20-25-02-2.png" style="width: 150px; height: 150px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem; --darkreader-inline-bgimage: initial; --darkreader-inline-bgcolor: #181a1b;" /><img alt="" data-darkreader-inline-bgcolor="" data-darkreader-inline-bgimage="" src="https://assets.leetcode.com/uploads/2024/06/03/screenshot-from-2024-06-03-20-24-12.png" style="width: 150px; height: 150px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem; --darkreader-inline-bgimage: initial; --darkreader-inline-bgcolor: #181a1b;" /></p>
</div>

<p><strong class="example">Example 2:</strong></p>

<div class="example-block">
<p><strong>Input:</strong> <span class="example-io">colors = [0,0,1,0,1,1], queries = [[1,3],[2,3,0],[1,5]]</span></p>

<p><strong>Output:</strong> <span class="example-io">[2,0]</span></p>

<p><strong>Explanation:</strong></p>

<p><img alt="" data-darkreader-inline-bgcolor="" data-darkreader-inline-bgimage="" src="https://assets.leetcode.com/uploads/2024/06/03/screenshot-from-2024-06-03-20-35-50.png" style="width: 150px; height: 150px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem; --darkreader-inline-bgimage: initial; --darkreader-inline-bgcolor: #181a1b;" /></p>

<p>First query:</p>

<p>Count of the alternating groups with size 3:</p>

<p><img alt="" data-darkreader-inline-bgcolor="" data-darkreader-inline-bgimage="" src="https://assets.leetcode.com/uploads/2024/06/03/screenshot-from-2024-06-03-20-37-13.png" style="width: 150px; height: 150px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem; --darkreader-inline-bgimage: initial; --darkreader-inline-bgcolor: #181a1b;" /><img alt="" data-darkreader-inline-bgcolor="" data-darkreader-inline-bgimage="" src="https://assets.leetcode.com/uploads/2024/06/03/screenshot-from-2024-06-03-20-36-40.png" style="width: 150px; height: 150px; padding: 10px; background: rgb(255, 255, 255); border-radius: 0.5rem; --darkreader-inline-bgimage: initial; --darkreader-inline-bgcolor: #181a1b;" /></p>

<p>Second query: <code>colors</code> will not change.</p>

<p>Third query: There is no alternating group with size 5.</p>
</div>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>4 &lt;= colors.length &lt;= 5 * 10<sup>4</sup></code></li>
	<li><code>0 &lt;= colors[i] &lt;= 1</code></li>
	<li><code>1 &lt;= queries.length &lt;= 5 * 10<sup>4</sup></code></li>
	<li><code>queries[i][0] == 1</code> or <code>queries[i][0] == 2</code></li>
	<li>For all <code>i</code> that:
	<ul>
		<li><code>queries[i][0] == 1</code>: <code>queries[i].length == 2</code>, <code>3 &lt;= queries[i][1] &lt;= colors.length - 1</code></li>
		<li><code>queries[i][0] == 2</code>: <code>queries[i].length == 3</code>, <code>0 &lt;= queries[i][1] &lt;= colors.length - 1</code>, <code>0 &lt;= queries[i][2] &lt;= 1</code></li>
	</ul>
	</li>
</ul>

import numpy as np
class Solution:
    def numberOfAlternatingGroups(self, colors, queries):
        N = len(colors)
        colors = np.tile(np.array(colors, dtype=bool), 2)  # wrap around
        print(colors)
        blocks = (colors[1:] != colors[:-1])  # runs of True will be "groups," but ending early by 1
        print(f'blocks:{blocks}')
        result = list()
        for query in queries:
            if query[0] == 1:
                size = query[1]
                blkcrop = blocks[:N + size - 1]  # crop to appropriate wrap around
                diff = (blkcrop[1:N + size - 1] != blocks[:N + size - 2])
                breaks = np.nonzero(diff)[0] + 1  # index of group beg/eng
                if blkcrop[+0]: breaks = np.concatenate([[0], breaks])
                if blkcrop[-1]: breaks = np.concatenate([breaks, [N + size - 2]])
                lens = breaks[1::2] - breaks[0::2] + 1  # lengths of the groups; +1 b/c they end early
                count = np.sum(np.maximum(0, lens - size + 1))  # size that can be packed into groups
                result.append(count)
            else:
                colors[query[1]:None:N] = query[2]
                blocks = (colors[1:] != colors[:-1])  # the simple update is only slightly slower
        return result

      
from sortedcontainers import SortedList
class Solution:
    def numberOfAlternatingGroups(self, colors: List[int], queries: List[List[int]]) -> List[int]:
        n = len(colors)
        def clamp(i):
            if i<0: return i+n
            if i>=n: return i-n
            return i
        sl = SortedList()
        for i in range(len(colors)):
            if colors[clamp(i)]==colors[clamp(i+1)]: sl.add(i)
        def getsl(ind):
            if ind<0: return sl[ind+len(sl)]-n
            elif ind>=len(sl): return sl[ind-len(sl)]+n
            else: return sl[ind]
        def getcount():
            c=Counter()
            if not sl: return c
            prev = getsl(-1)
            for i in sl:
                c[i-prev]+=1
                prev=i
            return c
        count=getcount()
        def decrease(v):
            count[v]-=1
            if count[v]==0: count.pop(v)
        def increase(v):
            count[v]+=1
        def togglesl(i):
            if i in sl: sl.remove(i)
            else: sl.add(i)
        res=[]
        for q in queries:
            if q[0]==1:
                # print(colors, sl, count)
                if len(sl)==0: res.append(n)
                else:
                    x = 0
                    for k,v in count.items():
                        if k<q[1]: continue
                        x += v * (k-q[1]+1)
                    res.append(x)
            else:
                _, i, col = q
                if colors[i]==col: continue
                colors[i]=col
                prev = clamp(i-1)
                if len(sl)<5:
                    togglesl(i)
                    togglesl(prev)
                    count = getcount()
                    continue
                elif i in sl:
                    ind = sl.bisect_left(i)
                    if prev in sl: 
                        lo = getsl(ind-2)
                        hi = getsl(ind+1)
                        decrease(i-1-lo)
                        decrease(1)
                        decrease(hi-i)
                        increase(hi-lo)
                    else:
                        lo = getsl(ind-1)
                        hi = getsl(ind+1)
                        decrease(i-lo)
                        decrease(hi-i)
                        increase(hi-i+1)
                        increase(i-lo-1)
                else:
                    if prev in sl:
                        ind = sl.bisect_left(prev)
                        lo = getsl(ind-1)
                        hi = getsl(ind+1)
                        decrease(prev-lo)
                        decrease(hi-prev)
                        increase(hi-prev-1)
                        increase(prev-lo+1)
                    else:
                        ind = sl.bisect_left(i)
                        hi = getsl(ind)
                        lo = getsl(ind-1)
                        decrease(hi-lo)
                        increase(i-1-lo)
                        increase(1)
                        increase(hi-i)
                togglesl(i)
                togglesl(prev)
        return res



52200