<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://program.sonsuz.us/feed.xml" rel="self" type="application/atom+xml" /><link href="https://program.sonsuz.us/" rel="alternate" type="text/html" /><updated>2026-09-25T12:05:52+00:00</updated><id>https://program.sonsuz.us/feed.xml</id><title type="html">SonsuzUs</title><subtitle>Programlama ve Yazılım</subtitle><author><name>Sonsuz Us</name></author><entry><title type="html">2-SAT Problemlerini SCC ile Doğrusal Zamanda Çözmek</title><link href="https://program.sonsuz.us/posts/2-sat-problemlerini-scc-ile-dogrusal-zamanda-cozmek/" rel="alternate" type="text/html" title="2-SAT Problemlerini SCC ile Doğrusal Zamanda Çözmek" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/2-sat-problemlerini-scc-ile-dogrusal-zamanda-cozmek</id><content type="html" xml:base="https://program.sonsuz.us/posts/2-sat-problemlerini-scc-ile-dogrusal-zamanda-cozmek/"><![CDATA[<p>Bir festivalde her etkinlik için “yapılsın” veya “yapılmasın” kararı verdiğimizi düşünelim. Kurallar ise “Konser yapılacaksa güvenlik ekibi gelsin” ya da “Ya konser ya tiyatro seçilsin” biçiminde olsun. Binlerce ikili karar birbirine bağlandığında deneme-yanılma yaklaşımı hızla çöker. 2-SAT, tam da bu tür sistemlerin çözülebilirliğini yönlü grafikler ve güçlü bağlı bileşenler sayesinde zarifçe belirler.</p>

<p>``</p>

<h2 id="2-sat-nedir">2-SAT nedir?</h2>

<p>2-SAT formülleri, her parantezinde en fazla iki literal bulunan ve bağlaçlarla birleştirilen ifadelerdir:</p>

\[(x_1 \lor \neg x_2) \land (x_2 \lor x_3) \land (\neg x_1 \lor \neg x_3)\]

<p>Literal, bir değişkenin kendisi ($x$) veya değili ($\neg x$) olabilir. Genel bir madde $(a \lor b)$ biçimindedir. Bu ifade yalnızca $a$ ve $b$ birlikte yanlış olduğunda bozulur. Dolayısıyla şu iki zorunluluğu türetebiliriz:</p>

\[(a \lor b) \equiv (\neg a \Rightarrow b) \land (\neg b \Rightarrow a)\]

<p>Her zorunluluğu yönlü bir kenara dönüştürürsek <strong>implikasyon grafiği</strong> ortaya çıkar.</p>

<table>
  <thead>
    <tr>
      <th>Mantıksal kısıt</th>
      <th>Grafiğe eklenen kenarlar</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$a \lor b$</td>
      <td>$\neg a \to b$, $\neg b \to a$</td>
    </tr>
    <tr>
      <td>$a \Rightarrow b$</td>
      <td>$a \to b$, $\neg b \to \neg a$</td>
    </tr>
    <tr>
      <td>$a$ doğru olmalı</td>
      <td>$\neg a \to a$</td>
    </tr>
    <tr>
      <td>$a$ ve $b$ eşit</td>
      <td>$a \to b$, $b \to a$, $\neg a \to \neg b$, $\neg b \to \neg a$</td>
    </tr>
  </tbody>
</table>

<h2 id="scc-neden-çözümü-belirliyor">SCC neden çözümü belirliyor?</h2>

<p>Bir güçlü bağlı bileşende, her düğümden diğer bütün düğümlere ulaşılabilir. Eğer $x$ ile $\neg x$ aynı SCC içindeyse hem $x \Rightarrow \neg x$ hem de $\neg x \Rightarrow x$ geçerlidir. Hangi doğruluk değerini seçersek seçelim sistem tersini de zorlar; formül çözülemez.</p>

<p>Böylece temel ölçüt şudur:</p>

\[\text{Formül çözülebilir} \iff \forall x_i,\ SCC(x_i) \ne SCC(\neg x_i)\]

<p>Bu, yönlü döngülerin mantıksal çelişkiyi görünür hâle getirmesidir. SCC’ler Tarjan veya Kosaraju algoritmasıyla $O(V+E)$ zamanda bulunur. $n$ değişken ve $m$ madde için grafikte $2n$ düğüm, $2m$ kenar bulunduğundan toplam karmaşıklık $O(n+m)$ olur.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th style="text-align: right">Zaman</th>
      <th>Büyük girdilerde durum</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Tüm atamaları denemek</td>
      <td style="text-align: right">$O(2^n)$</td>
      <td>Hızla kullanılamaz</td>
    </tr>
    <tr>
      <td>SCC tabanlı 2-SAT</td>
      <td style="text-align: right">$O(n+m)$</td>
      <td>Milyonlarca kısıta uygundur</td>
    </tr>
  </tbody>
</table>

<h2 id="kosaraju-ile-uygulama">Kosaraju ile uygulama</h2>

<p>Aşağıdaki C++ kodu, pozitif literali <code class="language-plaintext highlighter-rouge">2*x</code>, negatifini <code class="language-plaintext highlighter-rouge">2*x+1</code> ile temsil eder. <code class="language-plaintext highlighter-rouge">p^1</code> işlemi bir literalden karşıtına geçer. İlk DFS bitiş sırasını, ikinci DFS ise ters grafikte bileşenleri üretir.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">TwoSAT</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;</span> <span class="n">g</span><span class="p">,</span> <span class="n">rg</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">order</span><span class="p">,</span> <span class="n">comp</span><span class="p">,</span> <span class="n">used</span><span class="p">;</span>

    <span class="n">TwoSAT</span><span class="p">(</span><span class="kt">int</span> <span class="n">n</span><span class="p">)</span> <span class="o">:</span> <span class="n">n</span><span class="p">(</span><span class="n">n</span><span class="p">),</span> <span class="n">g</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">n</span><span class="p">),</span> <span class="n">rg</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">n</span><span class="p">),</span>
                    <span class="n">comp</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">n</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">),</span> <span class="n">used</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="n">n</span><span class="p">)</span> <span class="p">{}</span>

    <span class="c1">// (a OR b) maddesini implikasyon grafiğine ekler.</span>
    <span class="kt">void</span> <span class="nf">addClause</span><span class="p">(</span><span class="kt">int</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">g</span><span class="p">[</span><span class="n">a</span> <span class="o">^</span> <span class="mi">1</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
        <span class="n">rg</span><span class="p">[</span><span class="n">b</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">a</span> <span class="o">^</span> <span class="mi">1</span><span class="p">);</span>
        <span class="n">g</span><span class="p">[</span><span class="n">b</span> <span class="o">^</span> <span class="mi">1</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
        <span class="n">rg</span><span class="p">[</span><span class="n">a</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">b</span> <span class="o">^</span> <span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="nf">dfs1</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">used</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">u</span> <span class="o">:</span> <span class="n">g</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">used</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="n">dfs1</span><span class="p">(</span><span class="n">u</span><span class="p">);</span>
        <span class="n">order</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">void</span> <span class="nf">dfs2</span><span class="p">(</span><span class="kt">int</span> <span class="n">v</span><span class="p">,</span> <span class="kt">int</span> <span class="n">id</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">comp</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="n">id</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">u</span> <span class="o">:</span> <span class="n">rg</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="k">if</span> <span class="p">(</span><span class="n">comp</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">dfs2</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">id</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="kt">bool</span> <span class="nf">solve</span><span class="p">(</span><span class="n">vector</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;&amp;</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">v</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="o">*</span><span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">v</span><span class="p">)</span>
            <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">used</span><span class="p">[</span><span class="n">v</span><span class="p">])</span> <span class="n">dfs1</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>

        <span class="n">reverse</span><span class="p">(</span><span class="n">order</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">order</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
        <span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">v</span> <span class="o">:</span> <span class="n">order</span><span class="p">)</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">comp</span><span class="p">[</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="n">dfs2</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">id</span><span class="o">++</span><span class="p">);</span>

        <span class="n">value</span><span class="p">.</span><span class="n">resize</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">x</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">x</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="o">++</span><span class="n">x</span><span class="p">)</span> <span class="p">{</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">comp</span><span class="p">[</span><span class="mi">2</span><span class="o">*</span><span class="n">x</span><span class="p">]</span> <span class="o">==</span> <span class="n">comp</span><span class="p">[</span><span class="mi">2</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">])</span> <span class="k">return</span> <span class="nb">false</span><span class="p">;</span>
            <span class="n">value</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">=</span> <span class="n">comp</span><span class="p">[</span><span class="mi">2</span><span class="o">*</span><span class="n">x</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">comp</span><span class="p">[</span><span class="mi">2</span><span class="o">*</span><span class="n">x</span><span class="o">+</span><span class="mi">1</span><span class="p">];</span>
        <span class="p">}</span>
        <span class="k">return</span> <span class="nb">true</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">solve</code>, çelişki yoksa örnek bir doğruluk ataması da üretir. Bileşen numaralarına göre yapılan karşılaştırma, SCC’lerin yoğunlaştırılmış grafiğindeki ters topolojik sıradan yararlanır.</p>

<p>Sonuç olarak 2-SAT’ın gücü, mantığı kaba kuvvetle çözmek yerine onu erişilebilirlik problemine dönüştürmesinden gelir. Bir değişken kendi değiliyle aynı yönlü döngünün içine hapsolmuşsa çelişki kaçınılmazdır; aksi durumda bileşen sırası tutarlı bir atamayı doğrudan verir.</p>

<p><img src="/img/2-sat-problemlerini-73.svg" alt="2-sat-problemlerini-73" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="2-sat" /><category term="graf teorisi" /><category term="güçlü bağlı bileşenler" /><category term="algoritma" /><category term="kosaraju" /><category term="mantıksal kısıtlamalar" /><summary type="html"><![CDATA[Bir festivalde her etkinlik için “yapılsın” veya “yapılmasın” kararı verdiğimizi düşünelim. Kurallar ise “Konser yapılacaksa güvenlik ekibi gelsin” ya da “Ya konser ya tiyatro seçilsin” biçiminde olsun. Binlerce ikili karar birbirine bağlandığında deneme-yanılma yaklaşımı hızla çöker. 2-SAT, tam da bu tür sistemlerin çözülebilirliğini yönlü grafikler ve güçlü bağlı bileşenler sayesinde zarifçe belirler.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/2-sat-problemlerini-73.png" /><media:content medium="image" url="https://program.sonsuz.us/img/2-sat-problemlerini-73.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Fenwick Ağacı ile Çok Boyutlu Aralık Sorgularında Bellek Tasarrufu</title><link href="https://program.sonsuz.us/posts/fenwick-agaci-ile-cok-boyutlu-aralik-sorgularinda-bellek-tasarrufu/" rel="alternate" type="text/html" title="Fenwick Ağacı ile Çok Boyutlu Aralık Sorgularında Bellek Tasarrufu" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/fenwick-agaci-ile-cok-boyutlu-aralik-sorgularinda-bellek-tasarrufu</id><content type="html" xml:base="https://program.sonsuz.us/posts/fenwick-agaci-ile-cok-boyutlu-aralik-sorgularinda-bellek-tasarrufu/"><![CDATA[<p>Bir oyun haritasındaki kaynak miktarlarını, elektronik tablodaki hücre değerlerini veya koordinat düzlemindeki hareketli puanları sürekli güncellediğimizi düşünelim. Her değişiklikten sonra dikdörtgen bir bölgenin toplamını hesaplamak, naif yöntemle pahalıdır. Fenwick Ağacı ya da kısa adıyla <strong>BIT (Binary Indexed Tree)</strong>, segment ağacına göre daha az kod ve yardımcı bellek kullanarak bu işi logaritmik sürede yapar.</p>

<p>``</p>

<h2 id="fenwick-ağacının-temel-fikri">Fenwick Ağacının temel fikri</h2>

<p>Tek boyutlu BIT, her indeksin belirli uzunluktaki bir aralığın toplamını saklamasına dayanır. Bir indeksin sorumlu olduğu aralık, ikili gösterimindeki en düşük anlamlı bit ile belirlenir:</p>

\[lowbit(x)=x\ \&amp;\ (-x)\]

<p>Örneğin $12=(1100)_2$ için $lowbit(12)=4$ olur. Güncelleme sırasında indeksleri $lowbit(i)$ kadar artırır, önek toplamında ise aynı miktarı çıkarırız. Böylece her işlem en fazla $O(\log n)$ düğüme dokunur.</p>

<p>İki boyutta aynı düşünceyi satır ve sütun eksenlerine ayrı ayrı uygularız. $(x,y)$ noktasına eklenen değer, iki iç içe Fenwick yürüyüşüyle ilgili hücrelere taşınır. Bir dikdörtgen toplamı ise dahil etme–hariç tutma ilkesiyle bulunur:</p>

\[R(x_1,y_1,x_2,y_2)=P(x_2,y_2)-P(x_1-1,y_2)-P(x_2,y_1-1)+P(x_1-1,y_1-1)\]

<p>Burada $P(x,y)$, $(1,1)$ ile $(x,y)$ arasındaki önek toplamıdır.</p>

<h2 id="segment-ağacı-mı-fenwick-mi">Segment ağacı mı, Fenwick mi?</h2>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th style="text-align: right">2B Fenwick Ağacı</th>
      <th style="text-align: right">2B Segment Ağacı</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Nokta güncelleme</td>
      <td style="text-align: right">$O(\log n\log m)$</td>
      <td style="text-align: right">$O(\log n\log m)$</td>
    </tr>
    <tr>
      <td>Dikdörtgen toplamı</td>
      <td style="text-align: right">$O(\log n\log m)$</td>
      <td style="text-align: right">$O(\log n\log m)$</td>
    </tr>
    <tr>
      <td>Tipik yardımcı bellek</td>
      <td style="text-align: right">Yaklaşık $nm$</td>
      <td style="text-align: right">Yaklaşık $4n\cdot4m$</td>
    </tr>
    <tr>
      <td>Uygulama karmaşıklığı</td>
      <td style="text-align: right">Düşük</td>
      <td style="text-align: right">Yüksek</td>
    </tr>
    <tr>
      <td>Min/maks gibi işlemler</td>
      <td style="text-align: right">Sınırlı</td>
      <td style="text-align: right">Daha esnek</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/fenwick-agaci-ile-35.svg" alt="fenwick-agaci-ile-35" /></p>

<p>BIT’in önemli sınırlaması, işlemin tersinin bulunabilmesidir. Toplamada çıkarma sayesinde iki önekten aralık üretilebilir. Ancak genel minimum sorgusunda “önek minimumlarını çıkarma” diye bir işlem yoktur. Bu durumda segment ağacı daha doğru seçimdir.</p>

<h2 id="bellek-dostu-2b-uygulama">Bellek dostu 2B uygulama</h2>

<p>Aşağıdaki C++ sınıfı matrisi satır satır tek bir <code class="language-plaintext highlighter-rouge">vector</code> içinde tutar. Ayrı ayrı vektörler oluşturmadığı için tahsis maliyetini azaltır ve önbellek yerelliğini iyileştirir.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">class</span> <span class="nc">Fenwick2D</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="kt">long</span> <span class="kt">long</span><span class="o">&gt;</span> <span class="n">bit</span><span class="p">;</span>

    <span class="kt">long</span> <span class="kt">long</span><span class="o">&amp;</span> <span class="n">at</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">bit</span><span class="p">[</span><span class="n">x</span> <span class="o">*</span> <span class="p">(</span><span class="n">m</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">y</span><span class="p">];</span>
    <span class="p">}</span>

<span class="k">public</span><span class="o">:</span>
    <span class="n">Fenwick2D</span><span class="p">(</span><span class="kt">int</span> <span class="n">rows</span><span class="p">,</span> <span class="kt">int</span> <span class="n">cols</span><span class="p">)</span>
        <span class="o">:</span> <span class="n">n</span><span class="p">(</span><span class="n">rows</span><span class="p">),</span> <span class="n">m</span><span class="p">(</span><span class="n">cols</span><span class="p">),</span> <span class="n">bit</span><span class="p">((</span><span class="n">rows</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">*</span> <span class="p">(</span><span class="n">cols</span> <span class="o">+</span> <span class="mi">1</span><span class="p">),</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{}</span>

    <span class="c1">// (x, y) noktasına delta ekler.</span>
    <span class="kt">void</span> <span class="nf">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">,</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">delta</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="n">i</span> <span class="o">&amp;</span> <span class="o">-</span><span class="n">i</span><span class="p">)</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">y</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;=</span> <span class="n">m</span><span class="p">;</span> <span class="n">j</span> <span class="o">+=</span> <span class="n">j</span> <span class="o">&amp;</span> <span class="o">-</span><span class="n">j</span><span class="p">)</span>
                <span class="n">at</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span> <span class="o">+=</span> <span class="n">delta</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="c1">// (1,1) ile (x,y) arasındaki toplamı döndürür.</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="nf">prefix</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
        <span class="kt">long</span> <span class="kt">long</span> <span class="n">result</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span> <span class="n">i</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">-=</span> <span class="n">i</span> <span class="o">&amp;</span> <span class="o">-</span><span class="n">i</span><span class="p">)</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">y</span><span class="p">;</span> <span class="n">j</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">-=</span> <span class="n">j</span> <span class="o">&amp;</span> <span class="o">-</span><span class="n">j</span><span class="p">)</span>
                <span class="n">result</span> <span class="o">+=</span> <span class="n">at</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">long</span> <span class="kt">long</span> <span class="nf">rectangle</span><span class="p">(</span><span class="kt">int</span> <span class="n">x1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">x2</span><span class="p">,</span> <span class="kt">int</span> <span class="n">y2</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">prefix</span><span class="p">(</span><span class="n">x2</span><span class="p">,</span> <span class="n">y2</span><span class="p">)</span> <span class="o">-</span> <span class="n">prefix</span><span class="p">(</span><span class="n">x1</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">y2</span><span class="p">)</span>
             <span class="o">-</span> <span class="n">prefix</span><span class="p">(</span><span class="n">x2</span><span class="p">,</span> <span class="n">y1</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">prefix</span><span class="p">(</span><span class="n">x1</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">y1</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>

<p>İndekslerin <strong>1’den başlaması</strong> önemlidir; sıfır için <code class="language-plaintext highlighter-rouge">lowbit(0)</code> sıfırdır ve güncelleme döngüsü ilerlemez.</p>

<h2 id="boyutlar-devasa-olduğunda">Boyutlar devasa olduğunda</h2>

<p>Koordinatlar milyarlara ulaşıyor fakat yalnızca birkaç bin nokta kullanılıyorsa tam matris ayırmak anlamsızdır. Güncelleme ve sorgulardaki koordinatları sıralayıp benzersizleştirerek <strong>koordinat sıkıştırma</strong> uygulanabilir. Her gerçek koordinat, sıralamadaki 1 tabanlı sırasına dönüştürülür.</p>

<p>$d$ boyutta güncelleme ve sorgu maliyeti yaklaşık $O(\log^d n)$ olur. Buna karşılık yoğun depolama $O(n^d)$ büyüdüğünden, pratikte üç ve üzeri boyutlarda yalnızca erişilen Fenwick hücrelerini karma tablo veya sıkıştırılmış iç vektörlerle saklamak gerekir. Kısacası toplam ve frekans sorgularında BIT, küçük kodu ve düşük sabit maliyetiyle güçlüdür; karmaşık birleştirme işlemlerinde ise segment ağacı hâlâ sahnededir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="fenwick ağacı" /><category term="bit" /><category term="veri yapıları" /><category term="algoritma" /><category term="aralık sorguları" /><category term="bellek optimizasyonu" /><category term="cpp" /><summary type="html"><![CDATA[Bir oyun haritasındaki kaynak miktarlarını, elektronik tablodaki hücre değerlerini veya koordinat düzlemindeki hareketli puanları sürekli güncellediğimizi düşünelim. Her değişiklikten sonra dikdörtgen bir bölgenin toplamını hesaplamak, naif yöntemle pahalıdır. Fenwick Ağacı ya da kısa adıyla BIT (Binary Indexed Tree), segment ağacına göre daha az kod ve yardımcı bellek kullanarak bu işi logaritmik sürede yapar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/fenwick-agaci-ile-35.png" /><media:content medium="image" url="https://program.sonsuz.us/img/fenwick-agaci-ile-35.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">FFT ile Dev Sayıları O(N log N) Sürede Çarpmak</title><link href="https://program.sonsuz.us/posts/fft-ile-dev-sayilari-on-log-n-surede-carpmak/" rel="alternate" type="text/html" title="FFT ile Dev Sayıları O(N log N) Sürede Çarpmak" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/fft-ile-dev-sayilari-on-log-n-surede-carpmak</id><content type="html" xml:base="https://program.sonsuz.us/posts/fft-ile-dev-sayilari-on-log-n-surede-carpmak/"><![CDATA[<p>İlkokulda öğrendiğimiz uzun çarpma yöntemi küçük sayılarda harikadır; ancak milyonlarca basamak söz konusu olduğunda işler dramatik biçimde yavaşlar. Neyse ki sinyal işlemenin yıldızı Hızlı Fourier Dönüşümü, yani FFT, basamakları birer polinom katsayısı gibi ele alarak çarpma işlemini yaklaşık $O(N \log N)$ sürede gerçekleştirebilir.</p>

<p>``</p>

<h2 id="uzun-çarpma-neden-yavaş">Uzun çarpma neden yavaş?</h2>

<p>İki sayının da $N$ basamaklı olduğunu düşünelim. Geleneksel yöntemde birinci sayının her basamağı, ikinci sayının her basamağıyla çarpılır. Dolayısıyla yaklaşık $N^2$ işlem gerekir:</p>

\[T(N)=O(N^2)\]

<p>Basamak sayısı iki katına çıktığında çalışma miktarı yaklaşık dört katına çıkar. FFT tabanlı yaklaşımda ise büyüme çok daha sakindir:</p>

\[T(N)=O(N\log N)\]

<table>
  <thead>
    <tr>
      <th>Yöntem</th>
      <th style="text-align: right">Zaman karmaşıklığı</th>
      <th>Temel fikir</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Uzun çarpma</td>
      <td style="text-align: right">$O(N^2)$</td>
      <td>Tüm basamak çiftlerini çarp</td>
    </tr>
    <tr>
      <td>Karatsuba</td>
      <td style="text-align: right">$O(N^{1.585})$</td>
      <td>Çarpımları parçalayarak azalt</td>
    </tr>
    <tr>
      <td>FFT</td>
      <td style="text-align: right">$O(N\log N)$</td>
      <td>Konvolüsyonu frekans uzayında hesapla</td>
    </tr>
  </tbody>
</table>

<h2 id="sayıları-polinoma-dönüştürmek">Sayıları polinoma dönüştürmek</h2>

<p>Örneğin $1234$ sayısını şu polinomla temsil edebiliriz:</p>

\[A(x)=4+3x+2x^2+x^3\]

<p>Burada $x=10$ seçildiğinde yeniden 1234 elde edilir. İki sayıyı çarpmak, bunlara karşılık gelen polinomları çarpmaya eşdeğerdir. Polinom çarpımındaki katsayılar ise ayrık konvolüsyonla bulunur:</p>

\[c_k=\sum_{i=0}^{k}a_i b_{k-i}\]

<p>Bu formül doğrudan uygulanırsa yine $O(N^2)$ zaman harcar. FFT’nin sihri, konvolüsyonu noktasal çarpıma dönüştürmesidir:</p>

\[\operatorname{FFT}(a*b)=\operatorname{FFT}(a)\cdot\operatorname{FFT}(b)\]

<p>Yani önce katsayıları frekans uzayına taşır, karşılık gelen değerleri tek tek çarpar ve ters FFT ile geri döneriz.</p>

<h2 id="birim-kökler-ve-böl-parçala-yönet">Birim kökler ve böl-parçala-yönet</h2>

<p>Ayrık Fourier Dönüşümü şu şekilde tanımlanır:</p>

\[X_k=\sum_{j=0}^{N-1}x_j e^{-2\pi i jk/N}\]

<p>Üstel ifadeler, karmaşık düzlemde eşit aralıklarla yerleşmiş $N$’inci birim köklerdir. FFT, çift ve tek indeksli katsayıları ayırarak aynı hesaplamaları tekrar yapmaktan kurtulur. Her seviyede toplam $O(N)$ iş yapılır ve yaklaşık $\log_2N$ seviye bulunur.</p>

<table>
  <thead>
    <tr>
      <th>Alan</th>
      <th>İşlem</th>
      <th style="text-align: right">Maliyet</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Katsayı uzayı</td>
      <td>Konvolüsyon</td>
      <td style="text-align: right">$O(N^2)$</td>
    </tr>
    <tr>
      <td>Frekans uzayı</td>
      <td>Noktasal çarpım</td>
      <td style="text-align: right">$O(N)$</td>
    </tr>
    <tr>
      <td>FFT ve ters FFT</td>
      <td>Dönüşüm</td>
      <td style="text-align: right">$O(N\log N)$</td>
    </tr>
  </tbody>
</table>

<h2 id="python-ile-sade-bir-uygulama">Python ile sade bir uygulama</h2>

<p>Aşağıdaki örnek, sayıları onluk basamaklarına ayırır. NumPy FFT hesaplamasını yapar; son döngü ise yuvarlama ve elde taşıma işlemlerini düzeltir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">numpy</span> <span class="k">as</span> <span class="n">np</span>

<span class="k">def</span> <span class="nf">fft_multiply</span><span class="p">(</span><span class="n">x</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">y</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="n">a</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="nf">int</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">x</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]],</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span>
    <span class="n">b</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">array</span><span class="p">([</span><span class="nf">int</span><span class="p">(</span><span class="n">d</span><span class="p">)</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="n">y</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]],</span> <span class="n">dtype</span><span class="o">=</span><span class="nb">float</span><span class="p">)</span>

    <span class="n">size</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="k">while</span> <span class="n">size</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">a</span><span class="p">)</span> <span class="o">+</span> <span class="nf">len</span><span class="p">(</span><span class="n">b</span><span class="p">):</span>
        <span class="n">size</span> <span class="o">*=</span> <span class="mi">2</span>

    <span class="n">fa</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="nf">fft</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
    <span class="n">fb</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="nf">fft</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
    <span class="n">coefficients</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nf">rint</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">fft</span><span class="p">.</span><span class="nf">ifft</span><span class="p">(</span><span class="n">fa</span> <span class="o">*</span> <span class="n">fb</span><span class="p">).</span><span class="n">real</span><span class="p">).</span><span class="nf">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">int64</span><span class="p">)</span>

    <span class="n">carry</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">digits</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">coefficients</span><span class="p">:</span>
        <span class="n">total</span> <span class="o">=</span> <span class="nf">int</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">+</span> <span class="n">carry</span>
        <span class="n">digits</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">total</span> <span class="o">%</span> <span class="mi">10</span><span class="p">)</span>
        <span class="n">carry</span> <span class="o">=</span> <span class="n">total</span> <span class="o">//</span> <span class="mi">10</span>

    <span class="k">while</span> <span class="n">carry</span><span class="p">:</span>
        <span class="n">digits</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">carry</span> <span class="o">%</span> <span class="mi">10</span><span class="p">)</span>
        <span class="n">carry</span> <span class="o">//=</span> <span class="mi">10</span>

    <span class="k">while</span> <span class="nf">len</span><span class="p">(</span><span class="n">digits</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span> <span class="ow">and</span> <span class="n">digits</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
        <span class="n">digits</span><span class="p">.</span><span class="nf">pop</span><span class="p">()</span>

    <span class="k">return</span> <span class="sh">''</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="nf">map</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="n">digits</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">fft_multiply</span><span class="p">(</span><span class="sh">"</span><span class="s">123456789012345</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">987654321098765</span><span class="sh">"</span><span class="p">))</span>
</code></pre></div></div>

<p>Bu uygulama öğreticidir; kayan nokta hataları nedeniyle gerçekten milyonlarca basamakta güvenilir olmayabilir. Pratik sistemler basamakları daha büyük bloklara ayırır veya modüler aritmetik kullanan Sayı Teorik Dönüşümü’nü (NTT) tercih eder. Birden fazla asal modülle yapılan sonuçlar Çin Kalan Teoremi aracılığıyla birleştirilebilir.</p>

<p>Sonuçta FFT yalnızca ses ve görüntü analizi yapan bir araç değildir. Büyük sayı çarpımını polinom çarpımına, polinom çarpımını konvolüsyona ve konvolüsyonu ucuz noktasal çarpımlara dönüştüren güçlü bir algoritmik köprüdür.</p>

<p><img src="/img/fft-ile-dev-80.svg" alt="fft-ile-dev-80" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="fft" /><category term="algoritma" /><category term="matematik" /><category term="python" /><category term="büyük sayılar" /><category term="polinomlar" /><summary type="html"><![CDATA[İlkokulda öğrendiğimiz uzun çarpma yöntemi küçük sayılarda harikadır; ancak milyonlarca basamak söz konusu olduğunda işler dramatik biçimde yavaşlar. Neyse ki sinyal işlemenin yıldızı Hızlı Fourier Dönüşümü, yani FFT, basamakları birer polinom katsayısı gibi ele alarak çarpma işlemini yaklaşık $O(N \log N)$ sürede gerçekleştirebilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/fft-ile-dev-80.png" /><media:content medium="image" url="https://program.sonsuz.us/img/fft-ile-dev-80.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Karp’ın Minimum Ortalama Döngü Algoritmasıyla Graflarda Darboğaz Analizi</title><link href="https://program.sonsuz.us/posts/karpin-minimum-ortalama-dongu-algoritmasiyla-graflarda-darbogaz-analizi/" rel="alternate" type="text/html" title="Karp’ın Minimum Ortalama Döngü Algoritmasıyla Graflarda Darboğaz Analizi" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/karpin-minimum-ortalama-dongu-algoritmasiyla-graflarda-darbogaz-analizi</id><content type="html" xml:base="https://program.sonsuz.us/posts/karpin-minimum-ortalama-dongu-algoritmasiyla-graflarda-darbogaz-analizi/"><![CDATA[<p>Bir üretim hattı, işlemci görev zinciri veya ağ yönlendirme sistemi düşünün: İşler belirli durumlar arasında sürekli dolaşıyor ve her geçişin bir maliyeti var. Sistemin uzun vadeli sınırını çoğu zaman tek bir pahalı kenar değil, tekrar tekrar kullanılan bir döngünün ortalama maliyeti belirler. Richard Karp’ın minimum ortalama döngü algoritması, tam olarak bu gizli darboğazı polinom zamanda ortaya çıkarır.</p>

<p><img src="/img/karpin-minimum-ortalama-45.svg" alt="karpin-minimum-ortalama-45" /></p>

<p>``</p>

<h2 id="minimum-ortalama-döngü-nedir">Minimum ortalama döngü nedir?</h2>

<p>Yönlü ve ağırlıklı bir grafı $G=(V,E)$ olarak tanımlayalım. Bir $C$ döngüsünün ortalama ağırlığı, döngüdeki toplam maliyetin kenar sayısına bölünmesidir:</p>

\[μ(C)=\frac{\sum_{e \in C} w(e)}{\vert C\vert }\]

<p>Amaç, bütün yönlü döngüler arasında $μ(C)$ değerini en aza indirmektir. Burada aranan şey toplam ağırlığı en düşük döngü değildir. Örneğin iki kenarlı ve toplam ağırlığı 8 olan bir döngünün ortalaması 4; beş kenarlı ve toplam ağırlığı 10 olan başka bir döngünün ortalaması 2’dir. Toplam maliyeti daha yüksek olan ikinci döngü, uzun vadede daha avantajlıdır.</p>

<table>
  <thead>
    <tr>
      <th>Ölçüt</th>
      <th>Sorduğu soru</th>
      <th>Tipik kullanım</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>En kısa yol</td>
      <td>İki nokta arasında en ucuz rota hangisi?</td>
      <td>Navigasyon</td>
    </tr>
    <tr>
      <td>Minimum toplam döngü</td>
      <td>Toplam maliyeti en küçük döngü hangisi?</td>
      <td>Yerel optimizasyon</td>
    </tr>
    <tr>
      <td>Minimum ortalama döngü</td>
      <td>Her tekrar başına en ucuz döngü hangisi?</td>
      <td>Performans sınırı</td>
    </tr>
    <tr>
      <td>Maksimum akış</td>
      <td>Ağdan ne kadar veri geçirilebilir?</td>
      <td>Kapasite analizi</td>
    </tr>
  </tbody>
</table>

<h2 id="karpın-dinamik-programlama-fikri">Karp’ın dinamik programlama fikri</h2>

<p>Grafın $n=\vert V\vert $ düğümü olduğunu varsayalım. Bir başlangıç düğümü $s$ seçilir ve $d_k(v)$, tam olarak $k$ kenar kullanarak $s$ düğümünden $v$ düğümüne ulaşmanın minimum maliyeti olarak tanımlanır:</p>

\[d_k(v)=\min_{(u,v)\in E}\left(d_{k-1}(u)+w(u,v)\right)\]

<p>Başlangıçta $d_0(s)=0$, diğer değerler sonsuzdur. Karp’ın önemli sonucu, güçlü bağlı bir graf için minimum döngü ortalamasını şu formülle verir:</p>

\[μ^*=\min_{v\in V}\max_{0\leq k&lt;n}\frac{d_n(v)-d_k(v)}{n-k}\]

<p>Neden $n$ adım? Çünkü $n$ düğümlü bir graf üzerinde $n$ kenarlık bir yürüyüş mutlaka en az bir düğümü tekrar ziyaret eder; yani içinde bir döngü bulunur. Farklı $k$ noktalarından kalan parçaların ortalamaları karşılaştırıldığında, tekrarın sürdürülebilir en düşük maliyeti görünür hâle gelir.</p>

<h2 id="python-ile-uygulama">Python ile uygulama</h2>

<p>Aşağıdaki kod, düğümleri <code class="language-plaintext highlighter-rouge">0</code> ile <code class="language-plaintext highlighter-rouge">n-1</code> arasında numaralanmış bir graf için minimum ortalama değeri hesaplar:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">karp_minimum_cycle_mean</span><span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">edges</span><span class="p">,</span> <span class="n">source</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
    <span class="n">inf</span> <span class="o">=</span> <span class="nf">float</span><span class="p">(</span><span class="sh">"</span><span class="s">inf</span><span class="sh">"</span><span class="p">)</span>
    <span class="n">dp</span> <span class="o">=</span> <span class="p">[[</span><span class="n">inf</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)]</span>
    <span class="n">dp</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">source</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="c1"># Tam olarak k kenarlı en ucuz yürüyüşleri hesapla.
</span>    <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">weight</span> <span class="ow">in</span> <span class="n">edges</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">dp</span><span class="p">[</span><span class="n">k</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">u</span><span class="p">]</span> <span class="o">!=</span> <span class="n">inf</span><span class="p">:</span>
                <span class="n">candidate</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">k</span> <span class="o">-</span> <span class="mi">1</span><span class="p">][</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">weight</span>
                <span class="n">dp</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">=</span> <span class="nf">min</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">v</span><span class="p">],</span> <span class="n">candidate</span><span class="p">)</span>

    <span class="n">answer</span> <span class="o">=</span> <span class="n">inf</span>
    <span class="k">for</span> <span class="n">v</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="k">if</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">==</span> <span class="n">inf</span><span class="p">:</span>
            <span class="k">continue</span>

        <span class="n">worst_ratio</span> <span class="o">=</span> <span class="o">-</span><span class="n">inf</span>
        <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
            <span class="k">if</span> <span class="n">dp</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">!=</span> <span class="n">inf</span><span class="p">:</span>
                <span class="n">ratio</span> <span class="o">=</span> <span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="n">v</span><span class="p">]</span> <span class="o">-</span> <span class="n">dp</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">v</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">n</span> <span class="o">-</span> <span class="n">k</span><span class="p">)</span>
                <span class="n">worst_ratio</span> <span class="o">=</span> <span class="nf">max</span><span class="p">(</span><span class="n">worst_ratio</span><span class="p">,</span> <span class="n">ratio</span><span class="p">)</span>

        <span class="n">answer</span> <span class="o">=</span> <span class="nf">min</span><span class="p">(</span><span class="n">answer</span><span class="p">,</span> <span class="n">worst_ratio</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">answer</span>
</code></pre></div></div>

<p>Dinamik programlama tablosu $n+1$ satır ve $n$ sütun içerir. Her satırda bütün kenarlar gevşetildiği için zaman karmaşıklığı $O(nm)$, bellek karmaşıklığı ise $O(n^2)$ olur. Burada $m=\vert E\vert $ değeridir.</p>

<h2 id="darboğaz-analizindeki-anlamı">Darboğaz analizindeki anlamı</h2>

<p>Ağırlıklar gecikmeyi temsil ediyorsa minimum ortalama döngü, sistemde tekrar başına erişilebilecek en düşük maliyeti gösterir. Ağırlıklar kazanç veya kapasite olarak yorumlanıyorsa işaretleri değiştirerek maksimum ortalama döngü de bulunabilir. Böylece zamanlanmış devrelerde çevrim süresi, üretim ağlarında tekrar maliyeti ve olay sistemlerinde uzun dönem verimi analiz edilebilir.</p>

<p>Algoritmanın verdiği temel sonuç sayısal ortalamadır; döngünün kenarlarını doğrudan döndürmez. Gerçek döngüyü çıkarmak için öncül düğümler saklanmalı ve tekrar eden düğümler geriye doğru izlenmelidir. Ayrıca graf güçlü bağlı değilse her güçlü bağlı bileşeni ayrı incelemek, ulaşılamayan bölgelerin sonucu bozmasını engeller. Kısacası Karp’ın yaklaşımı, “Sistem sonsuza dek çalışırsa hangi tekrar performansı belirler?” sorusuna matematiksel ve uygulanabilir bir cevap verir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="graf algoritmaları" /><category term="karp algoritması" /><category term="dinamik programlama" /><category term="darboğaz analizi" /><category term="python" /><category term="optimizasyon" /><summary type="html"><![CDATA[Bir üretim hattı, işlemci görev zinciri veya ağ yönlendirme sistemi düşünün: İşler belirli durumlar arasında sürekli dolaşıyor ve her geçişin bir maliyeti var. Sistemin uzun vadeli sınırını çoğu zaman tek bir pahalı kenar değil, tekrar tekrar kullanılan bir döngünün ortalama maliyeti belirler. Richard Karp’ın minimum ortalama döngü algoritması, tam olarak bu gizli darboğazı polinom zamanda ortaya çıkarır.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/karpin-minimum-ortalama-45.png" /><media:content medium="image" url="https://program.sonsuz.us/img/karpin-minimum-ortalama-45.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Matris Üs Alma ile Devasa Doğrusal Tekrarlamalı Dizileri Hesaplamak</title><link href="https://program.sonsuz.us/posts/matris-us-alma-ile-devasa-dogrusal-tekrarlamali-dizileri-hesaplamak/" rel="alternate" type="text/html" title="Matris Üs Alma ile Devasa Doğrusal Tekrarlamalı Dizileri Hesaplamak" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/matris-us-alma-ile-devasa-dogrusal-tekrarlamali-dizileri-hesaplamak</id><content type="html" xml:base="https://program.sonsuz.us/posts/matris-us-alma-ile-devasa-dogrusal-tekrarlamali-dizileri-hesaplamak/"><![CDATA[<p>Fibonacci dizisinin milyonuncu, hatta milyarıncı terimini hesaplamak istediğimizi düşünelim. Diziyi baştan sona üretmek kolaydır; fakat bilgisayara milyarlarca kez toplama yaptırmak, çay demlenirken başlayıp yeni bir çay plantasyonu kurulunca biten bir plan olabilir. Neyse ki doğrusal tekrarlamaları matris biçiminde ifade ederek problemi $O(n)$ zamandan $O(\log n)$ zamana indirebiliriz.
``
Fibonacci dizisi şu bağıntıyla tanımlanır:</p>

\[F_n = F_{n-1} + F_{n-2}, \qquad F_0=0,\ F_1=1\]

<p>Klasik döngü yaklaşımı, önceki iki değeri saklayıp $F_2$’den $F_n$’e kadar ilerler. Bellek tüketimi $O(1)$ olsa da çalışma süresi $O(n)$ olur. Buradaki kritik gözlem, bir sonraki durumun mevcut durumun <strong>doğrusal dönüşümü</strong> olmasıdır.</p>

<p>Durumumuzu sütun vektörü olarak yazalım:</p>

\[\begin{bmatrix}
F_n \\
F_{n-1}
\end{bmatrix}
=
\begin{bmatrix}
1 &amp; 1 \\
1 &amp; 0
\end{bmatrix}
\begin{bmatrix}
F_{n-1} \\
F_{n-2}
\end{bmatrix}\]

<p>Buradaki dönüşüm matrisi $A$ olsun. Aynı dönüşümü tekrar tekrar uyguladığımızda matris kuvvetleri ortaya çıkar:</p>

\[\begin{bmatrix}
F_n \\
F_{n-1}
\end{bmatrix}
=A^{n-1}
\begin{bmatrix}
F_1 \\
F_0
\end{bmatrix}\]

<p>Yani artık hedefimiz diziyi adım adım yürütmek değil, $A^{n-1}$ matrisini hızlı hesaplamaktır.</p>

<table>
  <thead>
    <tr>
      <th>Yöntem</th>
      <th style="text-align: right">Zaman karmaşıklığı</th>
      <th style="text-align: right">Bellek</th>
      <th>Temel fikir</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Özyinelemeli Fibonacci</td>
      <td style="text-align: right">$O(2^n)$</td>
      <td style="text-align: right">$O(n)$</td>
      <td>Aynı alt problemleri tekrar hesaplar</td>
    </tr>
    <tr>
      <td>Döngü / dinamik programlama</td>
      <td style="text-align: right">$O(n)$</td>
      <td style="text-align: right">$O(1)$</td>
      <td>Terimleri sırayla üretir</td>
    </tr>
    <tr>
      <td>Matris üs alma</td>
      <td style="text-align: right">$O(\log n)$</td>
      <td style="text-align: right">$O(1)$</td>
      <td>Dönüşüm matrisini karesini alarak yükseltir</td>
    </tr>
  </tbody>
</table>

<h2 id="hızlı-üs-alma-neden-logaritmiktir">Hızlı üs alma neden logaritmiktir?</h2>

<p>Bir sayının kuvvetini hesaplarken kullanılan ikili üs alma tekniği matrislerde de geçerlidir. Üs çiftse</p>

\[A^n=(A^{n/2})^2\]

<p>olur. Üs tekse bir adet $A$ dışarı alınır:</p>

\[A^n=A\cdot A^{n-1}\]

<p>Her adımda üs yaklaşık yarıya indiği için yalnızca $\log_2 n$ tur gerekir. Matris boyutu Fibonacci için sabit, yani $2\times2$ olduğundan her çarpım sabit maliyetlidir.</p>

<p>Aşağıdaki C++ kodu sonucu bir modüler sayı altında hesaplar. Mod kullanmak önemlidir; çünkü Fibonacci sayıları son derece hızlı büyür ve standart tam sayı türlerine sığmaz.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;iostream&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">const</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">MOD</span> <span class="o">=</span> <span class="mi">1'000'000'007</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Matrix</span> <span class="p">{</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">a</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">]{};</span>
<span class="p">};</span>

<span class="n">Matrix</span> <span class="nf">multiply</span><span class="p">(</span><span class="k">const</span> <span class="n">Matrix</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">,</span> <span class="k">const</span> <span class="n">Matrix</span><span class="o">&amp;</span> <span class="n">y</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">Matrix</span> <span class="n">result</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">j</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="o">++</span><span class="n">j</span><span class="p">)</span>
            <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">k</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">;</span> <span class="o">++</span><span class="n">k</span><span class="p">)</span>
                <span class="n">result</span><span class="p">.</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span>
                    <span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">+</span> <span class="n">x</span><span class="p">.</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">*</span> <span class="n">y</span><span class="p">.</span><span class="n">a</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="n">j</span><span class="p">])</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">Matrix</span> <span class="nf">power</span><span class="p">(</span><span class="n">Matrix</span> <span class="n">base</span><span class="p">,</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">exponent</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">Matrix</span> <span class="n">result</span><span class="p">;</span>
    <span class="n">result</span><span class="p">.</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">result</span><span class="p">.</span><span class="n">a</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// Birim matris</span>

    <span class="k">while</span> <span class="p">(</span><span class="n">exponent</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">exponent</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span>
            <span class="n">result</span> <span class="o">=</span> <span class="n">multiply</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">base</span><span class="p">);</span>
        <span class="n">base</span> <span class="o">=</span> <span class="n">multiply</span><span class="p">(</span><span class="n">base</span><span class="p">,</span> <span class="n">base</span><span class="p">);</span>
        <span class="n">exponent</span> <span class="o">&gt;&gt;=</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="k">return</span> <span class="n">result</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">long</span> <span class="kt">long</span> <span class="nf">fibonacci</span><span class="p">(</span><span class="kt">long</span> <span class="kt">long</span> <span class="n">n</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="n">Matrix</span> <span class="n">transition</span><span class="p">{{{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">},</span> <span class="p">{</span><span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">}}};</span>
    <span class="k">return</span> <span class="n">power</span><span class="p">(</span><span class="n">transition</span><span class="p">,</span> <span class="n">n</span> <span class="o">-</span> <span class="mi">1</span><span class="p">).</span><span class="n">a</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">fibonacci</span><span class="p">(</span><span class="mi">1'000'000'000</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="sc">'\n'</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">multiply</code> iki dönüşümü birleştirir; <code class="language-plaintext highlighter-rouge">power</code> ise üssün ikili gösterimini kullanır. Başlangıçta sonuç birim matristir, çünkü $A^0=I$ olmalıdır. Üssün ilgili biti bir olduğunda mevcut taban sonuca katılır.</p>

<h2 id="yalnızca-fibonacci-değil">Yalnızca Fibonacci değil</h2>

<p>Bu yöntem, sabit katsayılı her doğrusal tekrarlamaya uygulanabilir. Örneğin</p>

\[X_n=2X_{n-1}+3X_{n-2}\]

<p>için dönüşüm matrisi</p>

\[\begin{bmatrix}
2 &amp; 3 \\
1 &amp; 0
\end{bmatrix}\]

<p>olur. Daha fazla geçmiş terime bağlı bağıntılarda matris boyutu büyür; mantık değişmez. Böylece matris, dizinin hafızasını taşıyan küçük bir zaman makinesine dönüşür: milyarlarca adımı tek tek yürümek yerine onları logaritmik sayıda sıçramayla geçer.</p>

<p><img src="/img/matris-us-alma-18.svg" alt="matris-us-alma-18" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="matris" /><category term="fibonacci" /><category term="algoritma" /><category term="dinamik-programlama" /><category term="hızlı-üs-alma" /><category term="c++" /><summary type="html"><![CDATA[Fibonacci dizisinin milyonuncu, hatta milyarıncı terimini hesaplamak istediğimizi düşünelim. Diziyi baştan sona üretmek kolaydır; fakat bilgisayara milyarlarca kez toplama yaptırmak, çay demlenirken başlayıp yeni bir çay plantasyonu kurulunca biten bir plan olabilir. Neyse ki doğrusal tekrarlamaları matris biçiminde ifade ederek problemi $O(n)$ zamandan $O(\log n)$ zamana indirebiliriz.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/matris-us-alma-18.png" /><media:content medium="image" url="https://program.sonsuz.us/img/matris-us-alma-18.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Min-Cost Max-Flow: Kapasite ve Maliyeti Aynı Anda Optimize Etmek</title><link href="https://program.sonsuz.us/posts/min-cost-max-flow-kapasite-ve-maliyeti-ayni-anda-optimize-etmek/" rel="alternate" type="text/html" title="Min-Cost Max-Flow: Kapasite ve Maliyeti Aynı Anda Optimize Etmek" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/min-cost-max-flow-kapasite-ve-maliyeti-ayni-anda-optimize-etmek</id><content type="html" xml:base="https://program.sonsuz.us/posts/min-cost-max-flow-kapasite-ve-maliyeti-ayni-anda-optimize-etmek/"><![CDATA[<p>Bir lojistik ağında mümkün olan en fazla ürünü taşımak yetmez; bunu hangi maliyetle yaptığınız da önemlidir. <strong>Min-Cost Max-Flow (MCMF)</strong>, kaynaktan hedefe maksimum akışı gönderirken toplam taşıma maliyetini en aza indiren algoritma ailesidir. Kısacası maksimum performans ile minimum fatura arasında matematiksel bir barış anlaşması imzalar.</p>

<p><img src="/img/min-cost-max-80.svg" alt="min-cost-max-80" /></p>

<p>``</p>

<h2 id="problemin-matematiksel-modeli">Problemin matematiksel modeli</h2>

<p>Yönlü bir ağdaki her $(u,v)$ kenarı iki değere sahiptir: kapasite $c(u,v)$ ve birim akış maliyeti $w(u,v)$. Kenardan geçirilen akış $f(u,v)$ ise şu koşulu sağlamalıdır:</p>

\[0 \leq f(u,v) \leq c(u,v)\]

<p>Kaynak $s$ ve hedef $t$ dışındaki her düğümde akış korunur:</p>

\[\sum_u f(u,v)=\sum_x f(v,x)\]

<p>Önce toplam akış miktarı $F$ maksimize edilir, ardından bu akışın maliyeti minimize edilir:</p>

\[C=\sum_{(u,v)\in E} f(u,v)\cdot w(u,v)\]

<p>Bu öncelik önemlidir. Sadece en ucuz yolu seçmek maksimum akışa ulaşmayı engelleyebilir; sadece maksimum akış bulmak ise gereksiz derecede pahalı bir sonuç üretebilir.</p>

<table>
  <thead>
    <tr>
      <th>Problem</th>
      <th>Amaç</th>
      <th>Kenar bilgisi</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>En kısa yol</td>
      <td>En ucuz tek rota</td>
      <td>Maliyet</td>
    </tr>
    <tr>
      <td>Maximum Flow</td>
      <td>En yüksek akış</td>
      <td>Kapasite</td>
    </tr>
    <tr>
      <td>Min-Cost Flow</td>
      <td>Belirli akışı ucuza taşıma</td>
      <td>Kapasite ve maliyet</td>
    </tr>
    <tr>
      <td>Min-Cost Max-Flow</td>
      <td>Maksimum akışı en ucuza taşıma</td>
      <td>Kapasite ve maliyet</td>
    </tr>
  </tbody>
</table>

<h2 id="artık-ağ-neden-gereklidir">Artık ağ neden gereklidir?</h2>

<p>Algoritma her seçimden sonra bir <strong>artık ağ (residual graph)</strong> tutar. Kapasitesi kullanılan ileri kenarın artık kapasitesi azalır; ters yönde ise maliyeti $-w(u,v)$ olan bir kenar oluşur. Bu ters kenar, algoritmanın önceki kararından vazgeçebilmesini sağlar. Yani sistem yalnızca ilerlemez; gerektiğinde “Bu rota pek iyi olmadı” diyerek akışı geri alıp daha ucuz biçimde düzenler.</p>

<p>Yaygın yaklaşım, artık ağda maliyeti en düşük artırma yolunu bulup mümkün olan akışı bu yoldan göndermektir. Negatif kenarlar nedeniyle Bellman-Ford kullanılabilir. Daha hızlı uygulamalarda ise düğüm potansiyelleriyle maliyetler yeniden ağırlıklandırılır ve Dijkstra çalıştırılır.</p>

<p>İndirgenmiş maliyet şu şekilde hesaplanır:</p>

\[w'(u,v)=w(u,v)+p(u)-p(v)\]

<p>Doğru potansiyeller altında $w’(u,v)\geq 0$ olur; böylece Dijkstra güvenle kullanılabilir.</p>

<h2 id="python-ile-temel-uygulama">Python ile temel uygulama</h2>

<p>Aşağıdaki sürüm, anlaşılır olması için SPFA ile en ucuz artırma yolunu bulur:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">collections</span> <span class="kn">import</span> <span class="n">deque</span>

<span class="k">class</span> <span class="nc">Edge</span><span class="p">:</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="n">self</span><span class="p">,</span> <span class="n">to</span><span class="p">,</span> <span class="n">rev</span><span class="p">,</span> <span class="n">cap</span><span class="p">,</span> <span class="n">cost</span><span class="p">):</span>
        <span class="n">self</span><span class="p">.</span><span class="n">to</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">rev</span> <span class="o">=</span> <span class="n">to</span><span class="p">,</span> <span class="n">rev</span>
        <span class="n">self</span><span class="p">.</span><span class="n">cap</span><span class="p">,</span> <span class="n">self</span><span class="p">.</span><span class="n">cost</span> <span class="o">=</span> <span class="n">cap</span><span class="p">,</span> <span class="n">cost</span>

<span class="k">def</span> <span class="nf">add_edge</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="n">cap</span><span class="p">,</span> <span class="n">cost</span><span class="p">):</span>
    <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="nf">append</span><span class="p">(</span><span class="nc">Edge</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">g</span><span class="p">[</span><span class="n">v</span><span class="p">]),</span> <span class="n">cap</span><span class="p">,</span> <span class="n">cost</span><span class="p">))</span>
    <span class="n">g</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="nf">append</span><span class="p">(</span><span class="nc">Edge</span><span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="nf">len</span><span class="p">(</span><span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">])</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="n">cost</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">min_cost_max_flow</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="n">source</span><span class="p">,</span> <span class="n">target</span><span class="p">):</span>
    <span class="n">n</span> <span class="o">=</span> <span class="nf">len</span><span class="p">(</span><span class="n">g</span><span class="p">)</span>
    <span class="n">flow</span> <span class="o">=</span> <span class="n">cost</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
        <span class="n">dist</span> <span class="o">=</span> <span class="p">[</span><span class="nf">float</span><span class="p">(</span><span class="sh">'</span><span class="s">inf</span><span class="sh">'</span><span class="p">)]</span> <span class="o">*</span> <span class="n">n</span>
        <span class="n">parent</span> <span class="o">=</span> <span class="p">[</span><span class="bp">None</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span>
        <span class="n">in_queue</span> <span class="o">=</span> <span class="p">[</span><span class="bp">False</span><span class="p">]</span> <span class="o">*</span> <span class="n">n</span>
        <span class="n">dist</span><span class="p">[</span><span class="n">source</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
        <span class="n">q</span> <span class="o">=</span> <span class="nf">deque</span><span class="p">([</span><span class="n">source</span><span class="p">])</span>

        <span class="k">while</span> <span class="n">q</span><span class="p">:</span>
            <span class="n">u</span> <span class="o">=</span> <span class="n">q</span><span class="p">.</span><span class="nf">popleft</span><span class="p">()</span>
            <span class="n">in_queue</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">=</span> <span class="bp">False</span>
            <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">e</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">]):</span>
                <span class="k">if</span> <span class="n">e</span><span class="p">.</span><span class="n">cap</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="ow">and</span> <span class="n">dist</span><span class="p">[</span><span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">]</span> <span class="o">&gt;</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">e</span><span class="p">.</span><span class="n">cost</span><span class="p">:</span>
                    <span class="n">dist</span><span class="p">[</span><span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">]</span> <span class="o">=</span> <span class="n">dist</span><span class="p">[</span><span class="n">u</span><span class="p">]</span> <span class="o">+</span> <span class="n">e</span><span class="p">.</span><span class="n">cost</span>
                    <span class="n">parent</span><span class="p">[</span><span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">u</span><span class="p">,</span> <span class="n">i</span><span class="p">)</span>
                    <span class="k">if</span> <span class="ow">not</span> <span class="n">in_queue</span><span class="p">[</span><span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">]:</span>
                        <span class="n">q</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">)</span>
                        <span class="n">in_queue</span><span class="p">[</span><span class="n">e</span><span class="p">.</span><span class="n">to</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span>

        <span class="k">if</span> <span class="n">parent</span><span class="p">[</span><span class="n">target</span><span class="p">]</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
            <span class="k">break</span>

        <span class="n">pushed</span> <span class="o">=</span> <span class="nf">float</span><span class="p">(</span><span class="sh">'</span><span class="s">inf</span><span class="sh">'</span><span class="p">)</span>
        <span class="n">v</span> <span class="o">=</span> <span class="n">target</span>
        <span class="k">while</span> <span class="n">v</span> <span class="o">!=</span> <span class="n">source</span><span class="p">:</span>
            <span class="n">u</span><span class="p">,</span> <span class="n">i</span> <span class="o">=</span> <span class="n">parent</span><span class="p">[</span><span class="n">v</span><span class="p">]</span>
            <span class="n">pushed</span> <span class="o">=</span> <span class="nf">min</span><span class="p">(</span><span class="n">pushed</span><span class="p">,</span> <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">i</span><span class="p">].</span><span class="n">cap</span><span class="p">)</span>
            <span class="n">v</span> <span class="o">=</span> <span class="n">u</span>

        <span class="n">v</span> <span class="o">=</span> <span class="n">target</span>
        <span class="k">while</span> <span class="n">v</span> <span class="o">!=</span> <span class="n">source</span><span class="p">:</span>
            <span class="n">u</span><span class="p">,</span> <span class="n">i</span> <span class="o">=</span> <span class="n">parent</span><span class="p">[</span><span class="n">v</span><span class="p">]</span>
            <span class="n">e</span> <span class="o">=</span> <span class="n">g</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">i</span><span class="p">]</span>
            <span class="n">e</span><span class="p">.</span><span class="n">cap</span> <span class="o">-=</span> <span class="n">pushed</span>
            <span class="n">g</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="n">e</span><span class="p">.</span><span class="n">rev</span><span class="p">].</span><span class="n">cap</span> <span class="o">+=</span> <span class="n">pushed</span>
            <span class="n">cost</span> <span class="o">+=</span> <span class="n">pushed</span> <span class="o">*</span> <span class="n">e</span><span class="p">.</span><span class="n">cost</span>
            <span class="n">v</span> <span class="o">=</span> <span class="n">u</span>

        <span class="n">flow</span> <span class="o">+=</span> <span class="n">pushed</span>

    <span class="k">return</span> <span class="n">flow</span><span class="p">,</span> <span class="n">cost</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">add_edge</code>, ileri kenarla birlikte ters kenarı da oluşturur. Ana döngü en ucuz yolu bulur, yol üzerindeki darboğaz kapasiteyi hesaplar ve artık ağı günceller. Sonuç <code class="language-plaintext highlighter-rouge">(maksimum_akış, minimum_maliyet)</code> biçimindedir.</p>

<h2 id="karmaşıklık-ve-kullanım-alanları">Karmaşıklık ve kullanım alanları</h2>

<p>SPFA tabanlı yaklaşım pratikte kullanışlı olsa da en kötü durumda yavaşlayabilir. Bellman-Ford ile yaklaşık $O(FVE)$, potansiyel ve Dijkstra ile $O(FE\log V)$ davranışı beklenir; burada $F$ artırma sayısıyla ilişkilidir.</p>

<p>MCMF; kargo dağıtımı, çalışan-görev eşleştirmesi, üretim planlama, ağ paketlerinin yönlendirilmesi ve kaynak tahsisi gibi alanlarda kullanılır. Özetle soru “Ne kadar taşıyabilirim?” ile bitmiyor, “Bunu en akıllıca kaça taşırım?” diye devam ediyorsa sahne Min-Cost Max-Flow’undur.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="algoritma" /><category term="graf" /><category term="ağ-akışı" /><category term="optimizasyon" /><category term="python" /><category term="min-cost-max-flow" /><summary type="html"><![CDATA[Bir lojistik ağında mümkün olan en fazla ürünü taşımak yetmez; bunu hangi maliyetle yaptığınız da önemlidir. Min-Cost Max-Flow (MCMF), kaynaktan hedefe maksimum akışı gönderirken toplam taşıma maliyetini en aza indiren algoritma ailesidir. Kısacası maksimum performans ile minimum fatura arasında matematiksel bir barış anlaşması imzalar.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/min-cost-max-80.png" /><media:content medium="image" url="https://program.sonsuz.us/img/min-cost-max-80.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Mo Algoritmasını Ağaçlara Uyarlamak: Euler Turu ile Çevrimdışı Sorgular</title><link href="https://program.sonsuz.us/posts/mo-algoritmasini-agaclara-uyarlamak-euler-turu-ile-cevrimdisi-sorgular/" rel="alternate" type="text/html" title="Mo Algoritmasını Ağaçlara Uyarlamak: Euler Turu ile Çevrimdışı Sorgular" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/mo-algoritmasini-agaclara-uyarlamak-euler-turu-ile-cevrimdisi-sorgular</id><content type="html" xml:base="https://program.sonsuz.us/posts/mo-algoritmasini-agaclara-uyarlamak-euler-turu-ile-cevrimdisi-sorgular/"><![CDATA[<p>Bir dizideki aralık sorgularını akıllıca sıralayıp tekrar kullanılabilir hesaplarla hızlandıran Mo algoritması, küçük bir Euler turu numarasıyla ağaçlarda da çalışabilir. Özellikle iki düğüm arasındaki yolda kaç farklı renk bulunduğu gibi sorgular, ağacı doğrusal bir yapıya dönüştürdüğümüzde bloklar hâlinde işlenebilir.</p>

<p><img src="/img/mo-algoritmasini-agaclara-19.svg" alt="mo-algoritmasini-agaclara-19" /></p>

<p>``</p>

<h2 id="önce-klasik-mo-mantığı">Önce klasik Mo mantığı</h2>

<p>Elimizde $Q$ adet $[L,R]$ sorgusu bulunan, uzunluğu $N$ olan bir dizi düşünelim. Her sorguyu bağımsız çözmek pahalıdır. Mo algoritması sorguları önce $L$ değerinin ait olduğu bloğa, ardından $R$ değerine göre sıralar. Blok boyutu genellikle $B \approx \sqrt{N}$ seçilir.</p>

<p>İki işaretçiyle güncel aralığı koruruz. Yeni sorguya geçerken elemanları yalnızca ekler veya çıkarırız. Ekleme ve çıkarma $O(1)$ ise yaklaşık karmaşıklık şöyledir:</p>

\[O((N+Q)\sqrt{N})\]

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Sorgu sırası</th>
      <th>Ara sonuç kullanımı</th>
      <th>Yaklaşık maliyet</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bağımsız çözüm</td>
      <td>Geliş sırası</td>
      <td>Yok</td>
      <td>$O(NQ)$</td>
    </tr>
    <tr>
      <td>Dizi üzerinde Mo</td>
      <td>Blok sırası</td>
      <td>Var</td>
      <td>$O((N+Q)\sqrt N)$</td>
    </tr>
    <tr>
      <td>Ağaç üzerinde Mo</td>
      <td>Euler aralıkları</td>
      <td>Var</td>
      <td>Genellikle $O((N+Q)\sqrt N)$</td>
    </tr>
  </tbody>
</table>

<h2 id="ağacı-diziye-çevirmek">Ağacı diziye çevirmek</h2>

<p>Ağaçta iki düğüm arasındaki yol doğrudan tek bir dizi aralığı değildir. Çözüm, DFS sırasında oluşturulan <strong>Euler turudur</strong>. Her düğümü ağaca girerken ve düğümden çıkarken kaydederiz. Böylece $N$ düğümlü ağaç için $2N$ uzunluğunda bir dizi oluşur.</p>

<p>Bir düğümün Euler aralığında kaç kez göründüğüne dikkat ederiz:</p>

<ul>
  <li>Bir kez görünüyorsa etkin kümededir.</li>
  <li>İki kez görünüyorsa iki ziyaret birbirini götürür.</li>
  <li>Hiç görünmüyorsa sorgunun yolunda değildir.</li>
</ul>

<p>Bu nedenle işaretçi bir Euler konumuna geldiğinde düğümü doğrudan eklemek yerine durumunu <strong>toggle</strong>, yani aç/kapat yaparız. Bu yaklaşım biraz ışık anahtarına benzer: aynı düğmeye ikinci kez basınca oda eski hâline döner.</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">euler</span><span class="p">,</span> <span class="n">color</span><span class="p">,</span> <span class="n">freq</span><span class="p">;</span>
<span class="n">vector</span><span class="o">&lt;</span><span class="kt">bool</span><span class="o">&gt;</span> <span class="n">active</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">distinctColors</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

<span class="kt">void</span> <span class="nf">toggle</span><span class="p">(</span><span class="kt">int</span> <span class="n">position</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">node</span> <span class="o">=</span> <span class="n">euler</span><span class="p">[</span><span class="n">position</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">c</span> <span class="o">=</span> <span class="n">color</span><span class="p">[</span><span class="n">node</span><span class="p">];</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">active</span><span class="p">[</span><span class="n">node</span><span class="p">])</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="o">--</span><span class="n">freq</span><span class="p">[</span><span class="n">c</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="n">distinctColors</span><span class="o">--</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">freq</span><span class="p">[</span><span class="n">c</span><span class="p">]</span><span class="o">++</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="n">distinctColors</span><span class="o">++</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">active</span><span class="p">[</span><span class="n">node</span><span class="p">]</span> <span class="o">=</span> <span class="o">!</span><span class="n">active</span><span class="p">[</span><span class="n">node</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Burada <code class="language-plaintext highlighter-rouge">freq[c]</code>, etkin düğümler arasında <code class="language-plaintext highlighter-rouge">c</code> renginin kaç defa bulunduğunu tutar. <code class="language-plaintext highlighter-rouge">distinctColors</code> ise güncel yol üzerindeki farklı renk sayısıdır. Renk değerleri büyükse önce koordinat sıkıştırma uygulanmalıdır.</p>

<h2 id="lca-neden-gerekiyor">LCA neden gerekiyor?</h2>

<p>$u$ ve $v$ düğümleri için önce giriş zamanlarına göre sıralama yapılır. Eğer $u$, $v$ düğümünün atasıysa yol uygun bir Euler aralığıyla temsil edilir. Değilse aralık, yolun büyük bölümünü kapsar fakat $LCA(u,v)$ düğümünü dışarıda bırakır.</p>

<p>Bu durumda sorgu cevaplanmadan hemen önce LCA geçici olarak etkinleştirilir, sonuç kaydedilir ve ardından tekrar kapatılır. İkili kaldırma kullanıldığında LCA hesabı $O(\log N)$ sürede yapılabilir.</p>

<table>
  <thead>
    <tr>
      <th>Durum</th>
      <th>Mo aralığı</th>
      <th>Ek işlem</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>$u$, $v$’nin atası</td>
      <td><code class="language-plaintext highlighter-rouge">tin[u]..tin[v]</code></td>
      <td>Yok</td>
    </tr>
    <tr>
      <td>Ayrı dallardalar</td>
      <td><code class="language-plaintext highlighter-rouge">tout[u]..tin[v]</code></td>
      <td>LCA geçici eklenir</td>
    </tr>
  </tbody>
</table>

<h2 id="sorguları-sıralamak">Sorguları sıralamak</h2>

<p>Her yol sorgusu, hesaplanan sol ve sağ Euler sınırlarıyla saklanır. Sonra klasik blok karşılaştırması uygulanır:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sort</span><span class="p">(</span><span class="n">queries</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">queries</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="p">[</span><span class="o">&amp;</span><span class="p">](</span><span class="k">const</span> <span class="n">Query</span><span class="o">&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="k">const</span> <span class="n">Query</span><span class="o">&amp;</span> <span class="n">b</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">blockA</span> <span class="o">=</span> <span class="n">a</span><span class="p">.</span><span class="n">left</span> <span class="o">/</span> <span class="n">blockSize</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">blockB</span> <span class="o">=</span> <span class="n">b</span><span class="p">.</span><span class="n">left</span> <span class="o">/</span> <span class="n">blockSize</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">blockA</span> <span class="o">!=</span> <span class="n">blockB</span><span class="p">)</span> <span class="k">return</span> <span class="n">blockA</span> <span class="o">&lt;</span> <span class="n">blockB</span><span class="p">;</span>

    <span class="c1">// Zikzak sıralama sağ işaretçinin hareketini azaltır.</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">blockA</span> <span class="o">&amp;</span> <span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">right</span> <span class="o">&gt;</span> <span class="n">b</span><span class="p">.</span><span class="n">right</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">right</span> <span class="o">&lt;</span> <span class="n">b</span><span class="p">.</span><span class="n">right</span><span class="p">;</span>
<span class="p">});</span>
</code></pre></div></div>

<p>Ağaç üzerinde Mo algoritması çevrimdışıdır; cevap vermeden önce bütün sorguları bilmek gerekir. Buna karşılık güncelleme bulunmayan, çok sayıda yol sorgusu içeren problemlerde oldukça güçlüdür. Özet tarif şudur: ağacı Euler turuyla düzleştir, sorguları bloklara ayır, düğümleri toggle et ve LCA’nın eksik kaldığı köşeleri dikkatle tamamla. Gerisi, iki işaretçinin ormanda düzenli bir yürüyüşünden ibarettir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="mo algoritması" /><category term="ağaç algoritmaları" /><category term="euler turu" /><category term="lca" /><category term="çevrimdışı sorgu" /><category term="c++" /><summary type="html"><![CDATA[Bir dizideki aralık sorgularını akıllıca sıralayıp tekrar kullanılabilir hesaplarla hızlandıran Mo algoritması, küçük bir Euler turu numarasıyla ağaçlarda da çalışabilir. Özellikle iki düğüm arasındaki yolda kaç farklı renk bulunduğu gibi sorgular, ağacı doğrusal bir yapıya dönüştürdüğümüzde bloklar hâlinde işlenebilir.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/mo-algoritmasini-agaclara-19.png" /><media:content medium="image" url="https://program.sonsuz.us/img/mo-algoritmasini-agaclara-19.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Möbius İnversiyonu ile Sayılar Teorisinde Kapsama-Dışlama</title><link href="https://program.sonsuz.us/posts/mobius-inversiyonu-ile-sayilar-teorisinde-kapsama-dislama/" rel="alternate" type="text/html" title="Möbius İnversiyonu ile Sayılar Teorisinde Kapsama-Dışlama" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/mobius-inversiyonu-ile-sayilar-teorisinde-kapsama-dislama</id><content type="html" xml:base="https://program.sonsuz.us/posts/mobius-inversiyonu-ile-sayilar-teorisinde-kapsama-dislama/"><![CDATA[<p>Bazı sayılar teorisi problemleri, bölenlerin ve ortak çarpanların iç içe geçmesi yüzünden çözülmez bir düğüm gibi görünür. Möbius inversiyonu ise bu düğümü tek tek açmak yerine matematiksel olarak tersine çevirir. Aralarında asal çiftleri saymaktan bölen toplamlarından özgün bir fonksiyonu geri kazanmaya kadar pek çok işlem, böylece zarif bir kapsama-dışlama hesabına dönüşür.</p>

<p><img src="/img/mobius-inversiyonu-ile-53.svg" alt="mobius-inversiyonu-ile-53" /></p>

<p>``</p>
<h2 id="möbius-fonksiyonu-nedir">Möbius fonksiyonu nedir?</h2>

<p>Möbius fonksiyonu $\mu(n)$, pozitif tam sayıları üç gruba ayırır:</p>

\[\mu(n)=
\begin{cases}
1, &amp; n=1,\\
0, &amp; n \text{ bir asalın karesine bölünüyorsa},\\
(-1)^k, &amp; n \text{ farklı } k \text{ asalın çarpımıysa}.
\end{cases}\]

<p>Örneğin $\mu(6)=1$ olur; çünkü $6=2\cdot3$ ve iki farklı asal çarpanı vardır. Buna karşılık $12$, $2^2$ ile bölündüğü için $\mu(12)=0$ değerini alır.</p>

<table>
  <thead>
    <tr>
      <th style="text-align: right">$n$</th>
      <th>Asal çarpan yapısı</th>
      <th style="text-align: right">$\mu(n)$</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td style="text-align: right">1</td>
      <td>Boş çarpım</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">6</td>
      <td>$2\cdot3$</td>
      <td style="text-align: right">1</td>
    </tr>
    <tr>
      <td style="text-align: right">30</td>
      <td>$2\cdot3\cdot5$</td>
      <td style="text-align: right">-1</td>
    </tr>
    <tr>
      <td style="text-align: right">12</td>
      <td>$2^2\cdot3$</td>
      <td style="text-align: right">0</td>
    </tr>
  </tbody>
</table>

<p>Fonksiyonun sihirli özelliği şudur:</p>

\[\sum_{d\mid n}\mu(d)=
\begin{cases}
1, &amp; n=1,\\
0, &amp; n&gt;1.
\end{cases}\]

<p>Bu eşitlik, istenmeyen ortak bölenleri artı ve eksi işaretlerle yok eden kapsama-dışlama ilkesinin aritmetik karşılığıdır.</p>

<h2 id="möbius-inversiyon-formülü">Möbius inversiyon formülü</h2>

<p>Bir $f$ fonksiyonunun bölenler üzerindeki toplamıyla $g$ fonksiyonu tanımlansın:</p>

\[g(n)=\sum_{d\mid n}f(d).\]

<p>Möbius inversiyonu, toplamın içine saklanmış $f$ değerini geri çıkarır:</p>

\[f(n)=\sum_{d\mid n}\mu(d)g\left(\frac{n}{d}\right).\]

<table>
  <thead>
    <tr>
      <th>İleri işlem</th>
      <th>Ters işlem</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Bölenlerden bilgi toplar</td>
      <td>Toplanan bilgiyi ayrıştırır</td>
    </tr>
    <tr>
      <td>$g(n)=\sum_{d\mid n}f(d)$</td>
      <td>$f(n)=\sum_{d\mid n}\mu(d)g(n/d)$</td>
    </tr>
    <tr>
      <td>Birikimli görünüm üretir</td>
      <td>Özgün katkıları bulur</td>
    </tr>
  </tbody>
</table>

<p>Bunun klasik örneği Euler’in totient fonksiyonudur. $n$ sayısının pozitif bölenlerinin totient değerleri toplamı $n$ eder:</p>

\[n=\sum_{d\mid n}\varphi(d).\]

<p>İnversiyon uygulandığında doğrudan şu formül elde edilir:</p>

\[\varphi(n)=\sum_{d\mid n}\mu(d)\frac{n}{d}.\]

<h2 id="aralarında-asal-çiftleri-saymak">Aralarında asal çiftleri saymak</h2>

<p>$1\leq a,b\leq N$ koşulunu sağlayan ve $\gcd(a,b)=1$ olan sıralı çiftleri sayalım. Bir çiftin her iki elemanı da $d$ ile bölünüyorsa yaklaşık değil, tam olarak $\lfloor N/d\rfloor^2$ seçenek vardır. Möbius fonksiyonu ortak bölenleri kapsama-dışlama ile temizler:</p>

\[C(N)=\sum_{d=1}^{N}\mu(d)\left\lfloor\frac{N}{d}\right\rfloor^2.\]

<p>Burada $\mu(d)=0$ olan kare çarpanlı değerler otomatik olarak elenir. Tek sayıda farklı asal içerenler çıkarılır, çift sayıda asal içerenler yeniden eklenir. Kısacası Möbius fonksiyonu, kapsama-dışlamanın muhasebecisidir; üstelik hesap makinesini hiç düşürmez!</p>

<h2 id="python-ile-doğrusal-elek">Python ile doğrusal elek</h2>

<p>Aşağıdaki kod, $1$ ile $N$ arasındaki Möbius değerlerini doğrusal zamanda üretir ve aralarında asal sıralı çiftlerin sayısını hesaplar:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">mobius_sieve</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="n">mu</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
    <span class="n">mu</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
    <span class="n">primes</span><span class="p">,</span> <span class="n">composite</span> <span class="o">=</span> <span class="p">[],</span> <span class="p">[</span><span class="bp">False</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">):</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="n">composite</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span>
            <span class="n">primes</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
            <span class="n">mu</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
        <span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="n">primes</span><span class="p">:</span>
            <span class="k">if</span> <span class="n">i</span> <span class="o">*</span> <span class="n">p</span> <span class="o">&gt;</span> <span class="n">n</span><span class="p">:</span>
                <span class="k">break</span>
            <span class="n">composite</span><span class="p">[</span><span class="n">i</span> <span class="o">*</span> <span class="n">p</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span>
            <span class="k">if</span> <span class="n">i</span> <span class="o">%</span> <span class="n">p</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
                <span class="n">mu</span><span class="p">[</span><span class="n">i</span> <span class="o">*</span> <span class="n">p</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
                <span class="k">break</span>
            <span class="n">mu</span><span class="p">[</span><span class="n">i</span> <span class="o">*</span> <span class="n">p</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="n">mu</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
    <span class="k">return</span> <span class="n">mu</span>


<span class="k">def</span> <span class="nf">coprime_pairs</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="n">mu</span> <span class="o">=</span> <span class="nf">mobius_sieve</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
    <span class="k">return</span> <span class="nf">sum</span><span class="p">(</span><span class="n">mu</span><span class="p">[</span><span class="n">d</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">n</span> <span class="o">//</span> <span class="n">d</span><span class="p">)</span> <span class="o">**</span> <span class="mi">2</span> <span class="k">for</span> <span class="n">d</span> <span class="ow">in</span> <span class="nf">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">n</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>

<span class="nf">print</span><span class="p">(</span><span class="nf">coprime_pairs</span><span class="p">(</span><span class="mi">10</span><span class="p">))</span>  <span class="c1"># 63
</span></code></pre></div></div>

<p>Elek her bileşik sayıyı kontrollü biçimde işler; böylece karmaşıklık $O(N)$, toplam hesabı da $O(N)$ olur. Büyük sınırlar için $\lfloor N/d\rfloor$ değerlerinin yalnızca yaklaşık $2\sqrt N$ farklı değer aldığından yararlanılarak gruplama yapılabilir.</p>

<p>Möbius inversiyonunu gördüğünüzde temel soruyu sorun: “Elimdeki fonksiyon, bölenler üzerinden birikmiş başka bir bilginin toplamı mı?” Yanıt evetse, tersine çevirme formülü büyük olasılıkla problemi birkaç satırlık temiz bir toplama indirecektir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="möbius inversiyonu" /><category term="sayılar teorisi" /><category term="kapsama-dışlama" /><category term="aralarında asallık" /><category term="bölen toplamları" /><category term="algoritma" /><summary type="html"><![CDATA[Bazı sayılar teorisi problemleri, bölenlerin ve ortak çarpanların iç içe geçmesi yüzünden çözülmez bir düğüm gibi görünür. Möbius inversiyonu ise bu düğümü tek tek açmak yerine matematiksel olarak tersine çevirir. Aralarında asal çiftleri saymaktan bölen toplamlarından özgün bir fonksiyonu geri kazanmaya kadar pek çok işlem, böylece zarif bir kapsama-dışlama hesabına dönüşür.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/mobius-inversiyonu-ile-53.png" /><media:content medium="image" url="https://program.sonsuz.us/img/mobius-inversiyonu-ile-53.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Persistent Segment Tree ile Zamanda Geriye Giden Dizi Sorguları</title><link href="https://program.sonsuz.us/posts/persistent-segment-tree-ile-zamanda-geriye-giden-dizi-sorgulari/" rel="alternate" type="text/html" title="Persistent Segment Tree ile Zamanda Geriye Giden Dizi Sorguları" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/persistent-segment-tree-ile-zamanda-geriye-giden-dizi-sorgulari</id><content type="html" xml:base="https://program.sonsuz.us/posts/persistent-segment-tree-ile-zamanda-geriye-giden-dizi-sorgulari/"><![CDATA[<p>Bir diziyi güncelledikten sonra eski değerlerine yeniden ihtiyaç duyduğunuzu düşünün. Normal bir Segment Tree değişiklikleri doğrudan mevcut yapı üzerinde uygular; geçmiş ise sessizce kaybolur. Persistent Segment Tree, her güncellemede yeni bir sürüm oluşturarak bu sorunu çözer. Üstelik bütün ağacı kopyalamak yerine yalnızca değişen düğümleri üretir. Kısacası elimizde veri yapılarının zaman makinesi vardır!
``</p>

<h2 id="kalıcılık-fikri-nedir">Kalıcılık fikri nedir?</h2>

<p>Persistent, yani <strong>kalıcı</strong>, bir veri yapısında önceki sürümler değişmeden erişilebilir kalır. Dizinin başlangıç durumuna <code class="language-plaintext highlighter-rouge">versiyon 0</code>, ilk güncellemeden sonraki durumuna <code class="language-plaintext highlighter-rouge">versiyon 1</code> diyebiliriz. Her versiyonun Segment Tree kökünü ayrı bir dizide saklamak yeterlidir.</p>

<p>Bir Segment Tree güncellemesinde kökten yaprağa yalnızca tek yol değişir. Dizinin boyutu $n$ ise bu yolun uzunluğu $O(\log n)$ olur. Dolayısıyla yeni sürüm için tüm $O(n)$ düğümleri kopyalamak yerine yaklaşık $O(\log n)$ yeni düğüm oluştururuz. Değişmeyen alt ağaçlar eski ve yeni sürümler tarafından ortak kullanılır.</p>

<p>$u$ güncelleme sonrasında toplam bellek maliyeti yaklaşık olarak:</p>

\[O(n + u \log n)\]

<p>Bu tekniğe <strong>path copying</strong>, yani yol kopyalama adı verilir.</p>

<table>
  <thead>
    <tr>
      <th>Özellik</th>
      <th style="text-align: right">Normal Segment Tree</th>
      <th style="text-align: right">Persistent Segment Tree</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Aralık sorgusu</td>
      <td style="text-align: right">$O(\log n)$</td>
      <td style="text-align: right">$O(\log n)$</td>
    </tr>
    <tr>
      <td>Noktasal güncelleme</td>
      <td style="text-align: right">$O(\log n)$</td>
      <td style="text-align: right">$O(\log n)$</td>
    </tr>
    <tr>
      <td>Geçmiş sürüme erişim</td>
      <td style="text-align: right">Yok</td>
      <td style="text-align: right">Var</td>
    </tr>
    <tr>
      <td>Güncelleme başına bellek</td>
      <td style="text-align: right">Ek düğüm yok</td>
      <td style="text-align: right">$O(\log n)$</td>
    </tr>
    <tr>
      <td>Uygulama karmaşıklığı</td>
      <td style="text-align: right">Daha kolay</td>
      <td style="text-align: right">Biraz daha dikkat ister</td>
    </tr>
  </tbody>
</table>

<h2 id="düğümler-nasıl-paylaşılır">Düğümler nasıl paylaşılır?</h2>

<p>Her düğüm; tuttuğu toplamı, sol çocuk indeksini ve sağ çocuk indeksini saklar. Güncelleme başladığında eski düğüm kopyalanır. Değişiklik hangi taraftaysa yalnızca o çocuk yeniden oluşturulur; diğer çocuğun indeksi eski sürümden alınır. Böylece iki farklı zaman çizgisi aynı değişmemiş dalları paylaşabilir.</p>

<p>Aşağıdaki C++ örneği, noktasal değer atama ve geçmiş bir sürümde aralık toplamı sorgulama işlemlerini gerçekleştirir:</p>

<div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;bits/stdc++.h&gt;</span><span class="cp">
</span><span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span>

<span class="k">struct</span> <span class="nc">Node</span> <span class="p">{</span>
    <span class="kt">long</span> <span class="kt">long</span> <span class="n">sum</span><span class="p">;</span>
    <span class="kt">int</span> <span class="n">left</span><span class="p">,</span> <span class="n">right</span><span class="p">;</span>
<span class="p">};</span>

<span class="n">vector</span><span class="o">&lt;</span><span class="n">Node</span><span class="o">&gt;</span> <span class="n">tree</span><span class="p">;</span>
<span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">roots</span><span class="p">;</span>

<span class="kt">int</span> <span class="nf">build</span><span class="p">(</span><span class="k">const</span> <span class="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&amp;</span> <span class="n">a</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">node</span> <span class="o">=</span> <span class="n">tree</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">tree</span><span class="p">.</span><span class="n">push_back</span><span class="p">({</span><span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">});</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">==</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">sum</span> <span class="o">=</span> <span class="n">a</span><span class="p">[</span><span class="n">l</span><span class="p">];</span>
        <span class="k">return</span> <span class="n">node</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
    <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">left</span> <span class="o">=</span> <span class="n">build</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">mid</span><span class="p">);</span>
    <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">right</span> <span class="o">=</span> <span class="n">build</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">);</span>
    <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">sum</span> <span class="o">=</span> <span class="n">tree</span><span class="p">[</span><span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">left</span><span class="p">].</span><span class="n">sum</span>
                   <span class="o">+</span> <span class="n">tree</span><span class="p">[</span><span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">right</span><span class="p">].</span><span class="n">sum</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">node</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">int</span> <span class="nf">update</span><span class="p">(</span><span class="kt">int</span> <span class="n">old</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">pos</span><span class="p">,</span> <span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="kt">int</span> <span class="n">node</span> <span class="o">=</span> <span class="n">tree</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
    <span class="n">tree</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">tree</span><span class="p">[</span><span class="n">old</span><span class="p">]);</span> <span class="c1">// Eski düğümün kopyası</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">l</span> <span class="o">==</span> <span class="n">r</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">sum</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">node</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">pos</span> <span class="o">&lt;=</span> <span class="n">mid</span><span class="p">)</span>
        <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">left</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">tree</span><span class="p">[</span><span class="n">old</span><span class="p">].</span><span class="n">left</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">mid</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">value</span><span class="p">);</span>
    <span class="k">else</span>
        <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">right</span> <span class="o">=</span> <span class="n">update</span><span class="p">(</span><span class="n">tree</span><span class="p">[</span><span class="n">old</span><span class="p">].</span><span class="n">right</span><span class="p">,</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">pos</span><span class="p">,</span> <span class="n">value</span><span class="p">);</span>

    <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">sum</span> <span class="o">=</span> <span class="n">tree</span><span class="p">[</span><span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">left</span><span class="p">].</span><span class="n">sum</span>
                   <span class="o">+</span> <span class="n">tree</span><span class="p">[</span><span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">right</span><span class="p">].</span><span class="n">sum</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">node</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">long</span> <span class="kt">long</span> <span class="nf">query</span><span class="p">(</span><span class="kt">int</span> <span class="n">node</span><span class="p">,</span> <span class="kt">int</span> <span class="n">l</span><span class="p">,</span> <span class="kt">int</span> <span class="n">r</span><span class="p">,</span> <span class="kt">int</span> <span class="n">ql</span><span class="p">,</span> <span class="kt">int</span> <span class="n">qr</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">qr</span> <span class="o">&lt;</span> <span class="n">l</span> <span class="o">||</span> <span class="n">r</span> <span class="o">&lt;</span> <span class="n">ql</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">ql</span> <span class="o">&lt;=</span> <span class="n">l</span> <span class="o">&amp;&amp;</span> <span class="n">r</span> <span class="o">&lt;=</span> <span class="n">qr</span><span class="p">)</span> <span class="k">return</span> <span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">sum</span><span class="p">;</span>

    <span class="kt">int</span> <span class="n">mid</span> <span class="o">=</span> <span class="p">(</span><span class="n">l</span> <span class="o">+</span> <span class="n">r</span><span class="p">)</span> <span class="o">/</span> <span class="mi">2</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">query</span><span class="p">(</span><span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">left</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">mid</span><span class="p">,</span> <span class="n">ql</span><span class="p">,</span> <span class="n">qr</span><span class="p">)</span>
         <span class="o">+</span> <span class="n">query</span><span class="p">(</span><span class="n">tree</span><span class="p">[</span><span class="n">node</span><span class="p">].</span><span class="n">right</span><span class="p">,</span> <span class="n">mid</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">r</span><span class="p">,</span> <span class="n">ql</span><span class="p">,</span> <span class="n">qr</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>İlk kök <code class="language-plaintext highlighter-rouge">roots.push_back(build(a, 0, n - 1))</code> ile kaydedilir. Yeni bir sürüm oluşturmak için <code class="language-plaintext highlighter-rouge">roots.push_back(update(roots.back(), 0, n - 1, konum, deger))</code> çağrılır. Örneğin üçüncü sürümde <code class="language-plaintext highlighter-rouge">[2, 6]</code> toplamı <code class="language-plaintext highlighter-rouge">query(roots[3], 0, n - 1, 2, 6)</code> ile bulunur.</p>

<h2 id="nerelerde-kullanılır">Nerelerde kullanılır?</h2>

<p>Persistent Segment Tree; geçmiş durum sorgularında, geri alma sistemlerinde, çevrim dışı sorgularda ve bir aralıktaki $k$’ıncı küçük elemanı bulma problemlerinde oldukça etkilidir. Git’in commit geçmişini düşünmek iyi bir benzetmedir: Her sürüm tamamen bağımsız görünür, fakat değişmeyen içerik yeniden kullanılabilir.</p>

<p>En önemli ayrıntı, eski düğümleri asla değiştirmemektir. Yanlışlıkla eski bir çocuk üzerinde güncelleme yapmak bütün zaman çizgisini bozabilir. Doğru uygulandığında ise geçmiş, silinen bir kayıt değil; yalnızca doğru kökü seçerek ziyaret edebileceğiniz başka bir versiyondur.</p>

<p><img src="/img/persistent-segment-tree-23.svg" alt="persistent-segment-tree-23" /></p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="persistent-segment-tree" /><category term="veri-yapıları" /><category term="algoritma" /><category term="c++" /><category term="segment-tree" /><category term="zaman-yolculuğu" /><summary type="html"><![CDATA[Bir diziyi güncelledikten sonra eski değerlerine yeniden ihtiyaç duyduğunuzu düşünün. Normal bir Segment Tree değişiklikleri doğrudan mevcut yapı üzerinde uygular; geçmiş ise sessizce kaybolur. Persistent Segment Tree, her güncellemede yeni bir sürüm oluşturarak bu sorunu çözer. Üstelik bütün ağacı kopyalamak yerine yalnızca değişen düğümleri üretir. Kısacası elimizde veri yapılarının zaman makinesi vardır!]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/persistent-segment-tree-23.png" /><media:content medium="image" url="https://program.sonsuz.us/img/persistent-segment-tree-23.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Tarama Çizgisi ile Dikdörtgenlerin Kesişim Alanını Bulmak</title><link href="https://program.sonsuz.us/posts/tarama-cizgisi-ile-dikdortgenlerin-kesisim-alanini-bulmak/" rel="alternate" type="text/html" title="Tarama Çizgisi ile Dikdörtgenlerin Kesişim Alanını Bulmak" /><published>2026-09-25T00:00:00+00:00</published><updated>2026-09-25T00:00:00+00:00</updated><id>https://program.sonsuz.us/posts/tarama-cizgisi-ile-dikdortgenlerin-kesisim-alanini-bulmak</id><content type="html" xml:base="https://program.sonsuz.us/posts/tarama-cizgisi-ile-dikdortgenlerin-kesisim-alanini-bulmak/"><![CDATA[<p>Düzlemde yüzlerce dikdörtgen bulunduğunu ve en az iki dikdörtgen tarafından kaplanan toplam alanı hesaplamamız gerektiğini düşünelim. Her dikdörtgen çiftini ayrı ayrı incelemek cazip görünür; ancak üçlü kesişimler aynı alanı defalarca saydırabilir. Tarama çizgisi, iki boyutlu bu karmaşayı dikey bir çizgiyi soldan sağa kaydırarak tek boyutlu aralık problemlerine dönüştürür.</p>

<p>``</p>

<h2 id="temel-fikir">Temel fikir</h2>

<p>Kenarları eksenlere paralel bir dikdörtgeni $(x_1,y_1,x_2,y_2)$ ile gösterelim. Dikey tarama çizgisi yalnızca bir dikdörtgenin sol veya sağ kenarına ulaştığında aktif dikdörtgen kümesi değişir. Bu nedenle her dikdörtgenden iki olay üretiriz:</p>

<ul>
  <li>$x_1$ konumunda dikdörtgenin $[y_1,y_2)$ aralığını ekle.</li>
  <li>$x_2$ konumunda aynı aralığı kaldır.</li>
</ul>

<p>Ardışık olay koordinatları $x_i$ ve $x_{i+1}$ arasında aktif küme sabittir. Bu şeritte en az iki kez kaplanan toplam dikey uzunluk $L_i$ ise alana katkı</p>

\[A_i=(x_{i+1}-x_i)L_i\]

<p>olur. Sonuç, bütün şeritlerin toplamıdır:</p>

\[A=\sum_i (x_{i+1}-x_i)L_i.\]

<p>Böylece alan hesabı, aktif $y$ aralıklarında en az iki kat örtülen uzunluğu bulma problemine indirgenir.</p>

<table>
  <thead>
    <tr>
      <th>Yaklaşım</th>
      <th>Avantaj</th>
      <th>Dezavantaj</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Dikdörtgen çiftlerini karşılaştırma</td>
      <td>Uygulaması kolaydır</td>
      <td>Üçlü kesişimleri tekrar sayabilir</td>
    </tr>
    <tr>
      <td>Hücre veya piksel tarama</td>
      <td>Sezgiseldir</td>
      <td>Büyük koordinatlarda aşırı maliyetlidir</td>
    </tr>
    <tr>
      <td>Sweep line</td>
      <td>Koordinat büyüklüğünden az etkilenir</td>
      <td>Olay yönetimi dikkat ister</td>
    </tr>
    <tr>
      <td>Sweep line + segment tree</td>
      <td>Büyük veri için hızlıdır</td>
      <td>Uygulaması daha karmaşıktır</td>
    </tr>
  </tbody>
</table>

<p><img src="/img/tarama-cizgisi-ile-31.svg" alt="tarama-cizgisi-ile-31" /></p>

<h2 id="orta-ölçekli-bir-python-çözümü">Orta ölçekli bir Python çözümü</h2>

<p>Aşağıdaki uygulama, her $x$ şeridinde aktif aralıkların uç noktalarını tarar. En az iki aralığın örttüğü dikey uzunluğu hesapladığı için üç veya daha fazla dikdörtgenin ortak bölgesi yalnızca bir kez alana eklenir.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">overlap_y_length</span><span class="p">(</span><span class="n">intervals</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">En az iki aktif aralık tarafından kaplanan y uzunluğunu döndürür.</span><span class="sh">"""</span>
    <span class="n">points</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">y1</span><span class="p">,</span> <span class="n">y2</span> <span class="ow">in</span> <span class="n">intervals</span><span class="p">:</span>
        <span class="n">points</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">y1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span>
        <span class="n">points</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">y2</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">))</span>

    <span class="n">points</span><span class="p">.</span><span class="nf">sort</span><span class="p">()</span>
    <span class="n">covered</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">count</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">previous_y</span> <span class="o">=</span> <span class="bp">None</span>

    <span class="k">for</span> <span class="n">y</span><span class="p">,</span> <span class="n">delta</span> <span class="ow">in</span> <span class="n">points</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">previous_y</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span> <span class="ow">and</span> <span class="n">count</span> <span class="o">&gt;=</span> <span class="mi">2</span><span class="p">:</span>
            <span class="n">covered</span> <span class="o">+=</span> <span class="n">y</span> <span class="o">-</span> <span class="n">previous_y</span>
        <span class="n">count</span> <span class="o">+=</span> <span class="n">delta</span>
        <span class="n">previous_y</span> <span class="o">=</span> <span class="n">y</span>

    <span class="k">return</span> <span class="n">covered</span>


<span class="k">def</span> <span class="nf">rectangle_overlap_area</span><span class="p">(</span><span class="n">rectangles</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">En az iki dikdörtgenin kapladığı birleşik kesişim alanını bulur.</span><span class="sh">"""</span>
    <span class="n">events</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">rect_id</span><span class="p">,</span> <span class="p">(</span><span class="n">x1</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">x2</span><span class="p">,</span> <span class="n">y2</span><span class="p">)</span> <span class="ow">in</span> <span class="nf">enumerate</span><span class="p">(</span><span class="n">rectangles</span><span class="p">):</span>
        <span class="n">events</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">x1</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">rect_id</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">))</span>   <span class="c1"># ekle
</span>        <span class="n">events</span><span class="p">.</span><span class="nf">append</span><span class="p">((</span><span class="n">x2</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="n">rect_id</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">))</span>  <span class="c1"># kaldır
</span>
    <span class="n">events</span><span class="p">.</span><span class="nf">sort</span><span class="p">()</span>
    <span class="n">active</span> <span class="o">=</span> <span class="p">{}</span>
    <span class="n">area</span> <span class="o">=</span> <span class="mi">0</span>
    <span class="n">previous_x</span> <span class="o">=</span> <span class="n">events</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">events</span> <span class="k">else</span> <span class="mi">0</span>
    <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span>

    <span class="k">while</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">events</span><span class="p">):</span>
        <span class="n">x</span> <span class="o">=</span> <span class="n">events</span><span class="p">[</span><span class="n">index</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span>
        <span class="n">width</span> <span class="o">=</span> <span class="n">x</span> <span class="o">-</span> <span class="n">previous_x</span>
        <span class="n">area</span> <span class="o">+=</span> <span class="n">width</span> <span class="o">*</span> <span class="nf">overlap_y_length</span><span class="p">(</span><span class="n">active</span><span class="p">.</span><span class="nf">values</span><span class="p">())</span>

        <span class="c1"># Aynı x koordinatındaki olayları birlikte uygula.
</span>        <span class="k">while</span> <span class="n">index</span> <span class="o">&lt;</span> <span class="nf">len</span><span class="p">(</span><span class="n">events</span><span class="p">)</span> <span class="ow">and</span> <span class="n">events</span><span class="p">[</span><span class="n">index</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">x</span><span class="p">:</span>
            <span class="n">_</span><span class="p">,</span> <span class="n">event_type</span><span class="p">,</span> <span class="n">rect_id</span><span class="p">,</span> <span class="n">y1</span><span class="p">,</span> <span class="n">y2</span> <span class="o">=</span> <span class="n">events</span><span class="p">[</span><span class="n">index</span><span class="p">]</span>
            <span class="k">if</span> <span class="n">event_type</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
                <span class="n">active</span><span class="p">[</span><span class="n">rect_id</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">y1</span><span class="p">,</span> <span class="n">y2</span><span class="p">)</span>
            <span class="k">else</span><span class="p">:</span>
                <span class="n">active</span><span class="p">.</span><span class="nf">pop</span><span class="p">(</span><span class="n">rect_id</span><span class="p">)</span>
            <span class="n">index</span> <span class="o">+=</span> <span class="mi">1</span>

        <span class="n">previous_x</span> <span class="o">=</span> <span class="n">x</span>

    <span class="k">return</span> <span class="n">area</span>

<span class="n">rectangles</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">3</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">6</span><span class="p">,</span> <span class="mi">5</span><span class="p">),</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">4</span><span class="p">)]</span>
<span class="nf">print</span><span class="p">(</span><span class="nf">rectangle_overlap_area</span><span class="p">(</span><span class="n">rectangles</span><span class="p">))</span>
</code></pre></div></div>

<h2 id="karmaşıklık-ve-geliştirme">Karmaşıklık ve geliştirme</h2>

<p>Her şeritte aktif aralıklar yeniden sıralandığından bu öğretici sürümün en kötü durum maliyeti yaklaşık $O(n^2\log n)$ olabilir. Büyük veri kümelerinde $y$ koordinatları sıkıştırılır ve bir segment tree üzerinde kapsama sayıları tutulur. Böylece güncellemeler $O(\log n)$ sürer ve toplam karmaşıklık $O(n\log n)$ düzeyine yaklaşır.</p>

<p>Sweep line’ın asıl güzelliği burada saklıdır: Alanı doğrudan hesaplamaya çalışmak yerine, yalnızca değişimin gerçekleştiği koordinatlara bakarız. Geometri bir anda olaylar, aralıklar ve küçük şeritlerin toplamı hâline gelir.</p>]]></content><author><name>Sonsuz Us</name></author><category term="Bilgi" /><category term="algoritma" /><category term="sweep-line" /><category term="hesaplamalı-geometri" /><category term="python" /><category term="dikdörtgen" /><category term="koordinat-sıkıştırma" /><summary type="html"><![CDATA[Düzlemde yüzlerce dikdörtgen bulunduğunu ve en az iki dikdörtgen tarafından kaplanan toplam alanı hesaplamamız gerektiğini düşünelim. Her dikdörtgen çiftini ayrı ayrı incelemek cazip görünür; ancak üçlü kesişimler aynı alanı defalarca saydırabilir. Tarama çizgisi, iki boyutlu bu karmaşayı dikey bir çizgiyi soldan sağa kaydırarak tek boyutlu aralık problemlerine dönüştürür.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://program.sonsuz.us/img/tarama-cizgisi-ile-31.png" /><media:content medium="image" url="https://program.sonsuz.us/img/tarama-cizgisi-ile-31.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry></feed>