<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://tzf0237.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://tzf0237.github.io/" rel="alternate" type="text/html" /><updated>2026-07-04T18:43:14+08:00</updated><id>https://tzf0237.github.io/feed.xml</id><title type="html">Zifan Tang’s Blog</title><subtitle>Zifan Tang&apos;s personal blog and portfolio</subtitle><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><entry><title type="html">算法竞赛（高级数据结构）——《算法竞赛》第4章</title><link href="https://tzf0237.github.io/posts/%E9%AB%98%E7%BA%A7%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/" rel="alternate" type="text/html" title="算法竞赛（高级数据结构）——《算法竞赛》第4章" /><published>2025-06-04T00:00:00+08:00</published><updated>2025-06-04T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/%E9%AB%98%E7%BA%A7%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84</id><content type="html" xml:base="https://tzf0237.github.io/posts/%E9%AB%98%E7%BA%A7%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"><![CDATA[<h1 id="算法竞赛第-4-章-高级数据结构">《算法竞赛》第 4 章 高级数据结构</h1>

<!-- more -->

<h2 id="1-并查集">1. 并查集</h2>

<h3 id="并查集的基本操作">并查集的基本操作</h3>

<p>DSU用于处理一些不相交结合的合并问题。</p>

<p><strong>初始化</strong>：表示 <code class="language-plaintext highlighter-rouge">s[i]</code> 是元素 <code class="language-plaintext highlighter-rouge">i</code> 所属的并查集。</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>s[i]=i;
</code></pre></div></div>

<p><strong>查询</strong>：查找元素属于哪个并查集。（路径压缩）</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">find_set</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span>
    <span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">!=</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">])</span> <span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span>
    <span class="k">return</span> <span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>合并</strong>：将两个元素并查集合并一起。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">join</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">int</span> <span class="n">fx</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">x</span><span class="p">),</span><span class="n">fy</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
    <span class="k">if</span><span class="p">(</span><span class="n">fx</span><span class="o">!=</span><span class="n">fy</span><span class="p">)</span> <span class="n">s</span><span class="p">[</span><span class="n">fx</span><span class="p">]</span><span class="o">=</span><span class="n">s</span><span class="p">[</span><span class="n">fy</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p>统计：<code class="language-plaintext highlighter-rouge">s[i]=i</code> 的数量就是并查集的数量。</p>

<h3 id="带权并查集">带权并查集</h3>

<p>额外定义一个权值数组 <code class="language-plaintext highlighter-rouge">d[]</code> ，把节点 i 到父节点的权值记为 <code class="language-plaintext highlighter-rouge">d[i]</code> 。</p>

<p><strong>带权路径压缩查询</strong></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">find_set</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">!=</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]){</span>
		<span class="kt">int</span> <span class="n">t</span><span class="o">=</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">];</span><span class="c1">//记录父节点</span>
		<span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span><span class="c1">//路径压缩</span>
		<span class="n">d</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">[</span><span class="n">t</span><span class="p">];</span><span class="c1">//更新x到祖宗节点的权值</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>带权合并</strong>：根据具体题意修改</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
</code></pre></div></div>

<h3 id="例题">例题</h3>

<p><a href="https://acm.hdu.edu.cn/showproblem.php?pid=3038">Problem - 3038</a></p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">2e5</span><span class="o">+</span><span class="mi">5</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">s</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">d</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">ans</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">find_set</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">!=</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]){</span>
		<span class="kt">int</span> <span class="n">t</span><span class="o">=</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">];</span><span class="c1">//记录父节点</span>
		<span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span><span class="c1">//路径压缩</span>
		<span class="n">d</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">[</span><span class="n">t</span><span class="p">];</span><span class="c1">//更新x到祖宗节点的权值</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">join</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">int</span> <span class="n">z</span><span class="p">){</span><span class="c1">//合并</span>
	<span class="kt">int</span> <span class="n">fx</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">x</span><span class="p">),</span><span class="n">fy</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">fx</span><span class="o">==</span><span class="n">fy</span><span class="p">){</span>
		<span class="k">if</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">-</span><span class="n">d</span><span class="p">[</span><span class="n">y</span><span class="p">]</span><span class="o">!=</span><span class="n">z</span><span class="p">)</span> <span class="n">ans</span><span class="o">++</span><span class="p">;</span>
	<span class="p">}</span><span class="k">else</span><span class="p">{</span>
		<span class="n">s</span><span class="p">[</span><span class="n">fx</span><span class="p">]</span><span class="o">=</span><span class="n">fy</span><span class="p">;</span>
		<span class="n">d</span><span class="p">[</span><span class="n">fx</span><span class="p">]</span><span class="o">=</span><span class="n">d</span><span class="p">[</span><span class="n">y</span><span class="p">]</span><span class="o">-</span><span class="n">d</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+</span><span class="n">z</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</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="n">N</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">i</span><span class="p">,</span><span class="n">d</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="n">ans</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="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">m</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
		<span class="kt">int</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="o">&gt;&gt;</span><span class="n">y</span><span class="o">&gt;&gt;</span><span class="n">z</span><span class="p">;</span>
		<span class="n">join</span><span class="p">(</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">ans</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="k">while</span><span class="p">(</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">)</span> <span class="n">solve</span><span class="p">();</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://www.luogu.com.cn/problem/P2024">P2024 食物链 - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">k</span><span class="p">,</span><span class="n">s</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">d</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">ans</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">find_set</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">!=</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]){</span>
		<span class="kt">int</span> <span class="n">t</span><span class="o">=</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">];</span><span class="c1">//记录父节点</span>
		<span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">]);</span><span class="c1">//路径压缩</span>
		<span class="n">d</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="n">t</span><span class="p">]</span><span class="o">+</span><span class="n">d</span><span class="p">[</span><span class="n">x</span><span class="p">])</span><span class="o">%</span><span class="mi">3</span><span class="p">;</span><span class="c1">//更新x到祖宗节点的权值</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">s</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">join</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">int</span> <span class="n">z</span><span class="p">){</span><span class="c1">//合并</span>
	<span class="kt">int</span> <span class="n">fx</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">x</span><span class="p">),</span><span class="n">fy</span><span class="o">=</span><span class="n">find_set</span><span class="p">(</span><span class="n">y</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">fx</span><span class="o">==</span><span class="n">fy</span><span class="p">){</span>
		<span class="k">if</span><span class="p">((</span><span class="n">z</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">d</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">-</span><span class="n">d</span><span class="p">[</span><span class="n">y</span><span class="p">]</span><span class="o">+</span><span class="mi">3</span><span class="p">)</span><span class="o">%</span><span class="mi">3</span><span class="p">))</span> <span class="n">ans</span><span class="o">++</span><span class="p">;</span>
	<span class="p">}</span><span class="k">else</span><span class="p">{</span>
		<span class="n">s</span><span class="p">[</span><span class="n">fx</span><span class="p">]</span><span class="o">=</span><span class="n">fy</span><span class="p">;</span>
		<span class="n">d</span><span class="p">[</span><span class="n">fx</span><span class="p">]</span><span class="o">=</span><span class="p">(</span><span class="n">d</span><span class="p">[</span><span class="n">y</span><span class="p">]</span><span class="o">-</span><span class="n">d</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+</span><span class="n">z</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">%</span><span class="mi">3</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</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="n">N</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">i</span><span class="p">,</span><span class="n">d</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
		<span class="kt">int</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">z</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="o">&gt;&gt;</span><span class="n">y</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;</span><span class="n">n</span><span class="o">||</span><span class="n">y</span><span class="o">&gt;</span><span class="n">n</span><span class="o">||</span><span class="p">(</span><span class="n">z</span><span class="o">==</span><span class="mi">2</span><span class="o">&amp;&amp;</span><span class="n">x</span><span class="o">==</span><span class="n">y</span><span class="p">))</span> <span class="n">ans</span><span class="o">++</span><span class="p">;</span>
		<span class="k">else</span> <span class="n">join</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">z</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">ans</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="2树状数组">2.树状数组</h2>

<p>树状数组可以 \(O(log_2n)\) 的时间查询和维护前缀和，前缀和可以用来区间修改或者区间查询。</p>

<p>需要借助一个神奇的函数 <code class="language-plaintext highlighter-rouge">#define lowbit(x) ((x)&amp;-(x))</code>。</p>

<p>如果当前节点为 x ，父节点为 <code class="language-plaintext highlighter-rouge">x+lowbit(x)</code>。</p>

<p>在树状数组中，每个元素 \(tree[]\) 中存储的是区间 \([x-lowbit(x)+1,x]\) 中每个数之和。</p>

<h3 id="单点修改区间查询"><strong>单点修改+区间查询</strong></h3>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define lowbit(x) ((x)&amp;-(x))
</span><span class="kt">int</span> <span class="n">tree</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">update</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">d</span><span class="p">){</span><span class="c1">//单点修改</span>
	<span class="k">while</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="n">tree</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span>
		<span class="n">x</span><span class="o">+=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">sum</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span><span class="c1">//查询前缀和</span>
	<span class="kt">int</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;</span><span class="mi">0</span><span class="p">){</span>
		<span class="n">ans</span><span class="o">+=</span><span class="n">tree</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
		<span class="n">x</span><span class="o">-=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</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">1</span><span class="p">,</span><span class="n">x</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="mi">10</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">x</span><span class="p">);</span><span class="c1">//初始计算tree[]数组</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"[5,8]="</span><span class="o">&lt;&lt;</span><span class="n">sum</span><span class="p">(</span><span class="mi">8</span><span class="p">)</span><span class="o">-</span><span class="n">sum</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="区间修改单点查询"><strong>区间修改+单点查询</strong></h3>

<p><a href="https://acm.hdu.edu.cn/showproblem.php?pid=1556">Problem - 1556</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define lowbit(x) ((x)&amp;-(x))
</span><span class="kt">int</span> <span class="n">tree</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">n</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">update</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">d</span><span class="p">){</span><span class="c1">//单点修改</span>
	<span class="k">while</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="n">tree</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span>
		<span class="n">x</span><span class="o">+=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">sum</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span><span class="c1">//查询前缀和</span>
	<span class="kt">int</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;</span><span class="mi">0</span><span class="p">){</span>
		<span class="n">ans</span><span class="o">+=</span><span class="n">tree</span><span class="p">[</span><span class="n">x</span><span class="p">];</span>
		<span class="n">x</span><span class="o">-=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">memset</span><span class="p">(</span><span class="n">tree</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">tree</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">1</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="p">){</span>
		<span class="kt">int</span> <span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">l</span><span class="o">&gt;&gt;</span><span class="n">r</span><span class="p">;</span>
		<span class="n">update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span>
		<span class="n">update</span><span class="p">(</span><span class="n">r</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="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">1</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="p">){</span>
		<span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="o">!=</span><span class="n">n</span><span class="p">)</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">sum</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">" "</span><span class="p">;</span>
		<span class="k">else</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">sum</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="区间修改区间查询"><strong>区间修改+区间查询</strong></h3>

<p><a href="https://www.luogu.com.cn/problem/P3372">P3372 【模板】线段树 1 - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ll</span> <span class="n">tree1</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">tree2</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">n</span><span class="p">,</span><span class="n">m</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">update1</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">,</span><span class="n">ll</span> <span class="n">d</span><span class="p">){</span><span class="k">while</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="n">tree1</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span><span class="n">x</span><span class="o">+=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);}}</span>
<span class="kt">void</span> <span class="n">update2</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">,</span><span class="n">ll</span> <span class="n">d</span><span class="p">){</span><span class="k">while</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="n">tree2</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span><span class="n">x</span><span class="o">+=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);}}</span>
<span class="n">ll</span> <span class="n">sum1</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">){</span><span class="n">ll</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;</span><span class="mi">0</span><span class="p">){</span><span class="n">ans</span><span class="o">+=</span><span class="n">tree1</span><span class="p">[</span><span class="n">x</span><span class="p">];</span><span class="n">x</span><span class="o">-=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);}</span> <span class="k">return</span> <span class="n">ans</span><span class="p">;}</span>
<span class="n">ll</span> <span class="n">sum2</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">){</span><span class="n">ll</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;</span><span class="mi">0</span><span class="p">){</span><span class="n">ans</span><span class="o">+=</span><span class="n">tree2</span><span class="p">[</span><span class="n">x</span><span class="p">];</span><span class="n">x</span><span class="o">-=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">x</span><span class="p">);}</span> <span class="k">return</span> <span class="n">ans</span><span class="p">;}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">;</span>
	<span class="n">ll</span> <span class="n">old</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">x</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">1</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="p">){</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="p">;</span>
		<span class="n">update1</span><span class="p">(</span><span class="n">i</span><span class="p">,</span><span class="n">x</span><span class="o">-</span><span class="n">old</span><span class="p">);</span><span class="c1">//差分数组初始化</span>
		<span class="n">update2</span><span class="p">(</span><span class="n">i</span><span class="p">,(</span><span class="n">i</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">x</span><span class="o">-</span><span class="n">old</span><span class="p">));</span>
		<span class="n">old</span><span class="o">=</span><span class="n">x</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
		<span class="n">ll</span> <span class="n">q</span><span class="p">,</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">d</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">q</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">q</span><span class="o">==</span><span class="mi">1</span><span class="p">){</span>
			<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">l</span><span class="o">&gt;&gt;</span><span class="n">r</span><span class="o">&gt;&gt;</span><span class="n">d</span><span class="p">;</span>
			<span class="n">update1</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">d</span><span class="p">);</span>
			<span class="n">update1</span><span class="p">(</span><span class="n">r</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="n">d</span><span class="p">);</span>
			<span class="n">update2</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">d</span><span class="o">*</span><span class="p">(</span><span class="n">l</span><span class="o">-</span><span class="mi">1</span><span class="p">));</span>
			<span class="n">update2</span><span class="p">(</span><span class="n">r</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="n">d</span><span class="o">*</span><span class="n">r</span><span class="p">);</span>
		<span class="p">}</span><span class="k">else</span><span class="p">{</span>
			<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">l</span><span class="o">&gt;&gt;</span><span class="n">r</span><span class="p">;</span>
			<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="p">(</span><span class="n">r</span><span class="o">*</span><span class="n">sum1</span><span class="p">(</span><span class="n">r</span><span class="p">)</span><span class="o">-</span><span class="n">sum2</span><span class="p">(</span><span class="n">r</span><span class="p">)</span><span class="o">-</span><span class="p">(</span><span class="n">l</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">sum1</span><span class="p">(</span><span class="n">l</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">+</span><span class="n">sum2</span><span class="p">(</span><span class="n">l</span><span class="o">-</span><span class="mi">1</span><span class="p">))</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="二维区间修改区间查询">二维区间修改+区间查询</h3>

<p><a href="https://www.luogu.com.cn/problem/P4514">P4514 上帝造题的七分钟 - 洛谷</a></p>

<p>采用CDQ分治更好。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">t1</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">],</span><span class="n">t2</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">],</span><span class="n">t3</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">],</span><span class="n">t4</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">],</span><span class="n">n</span><span class="p">,</span><span class="n">m</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">update</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">int</span> <span class="n">d</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">lowbit</span><span class="p">(</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">lowbit</span><span class="p">(</span><span class="n">j</span><span class="p">)){</span>
			<span class="n">t1</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">d</span><span class="p">;</span><span class="n">t2</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="o">*</span><span class="n">d</span><span class="p">;</span>
			<span class="n">t3</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">y</span><span class="o">*</span><span class="n">d</span><span class="p">;</span><span class="n">t4</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="o">*</span><span class="n">y</span><span class="o">*</span><span class="n">d</span><span class="p">;</span>
		<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">sum</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">int</span> <span class="n">ans</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">lowbit</span><span class="p">(</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">lowbit</span><span class="p">(</span><span class="n">j</span><span class="p">))</span>
			<span class="n">ans</span><span class="o">+=</span><span class="p">(</span><span class="n">x</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">y</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">t1</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">y</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">t2</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">x</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">t3</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">t4</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">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="kt">char</span> <span class="n">ch</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">ch</span><span class="p">;</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">ch</span><span class="p">){</span>
		<span class="kt">int</span> <span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">,</span><span class="n">d</span><span class="p">,</span><span class="n">del</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="o">&gt;&gt;</span><span class="n">b</span><span class="o">&gt;&gt;</span><span class="n">c</span><span class="o">&gt;&gt;</span><span class="n">d</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">ch</span><span class="o">==</span><span class="sc">'L'</span><span class="p">){</span>
			<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">del</span><span class="p">;</span>
			<span class="n">update</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">del</span><span class="p">);</span><span class="n">update</span><span class="p">(</span><span class="n">c</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">d</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">del</span><span class="p">);</span>
			<span class="n">update</span><span class="p">(</span><span class="n">a</span><span class="p">,</span><span class="n">d</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="n">del</span><span class="p">);</span><span class="n">update</span><span class="p">(</span><span class="n">c</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="o">-</span><span class="n">del</span><span class="p">);</span>
		<span class="p">}</span>
		<span class="k">else</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">sum</span><span class="p">(</span><span class="n">c</span><span class="p">,</span><span class="n">d</span><span class="p">)</span><span class="o">+</span><span class="n">sum</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">b</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">-</span><span class="n">sum</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">d</span><span class="p">)</span><span class="o">-</span><span class="n">sum</span><span class="p">(</span><span class="n">c</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="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="3线段树">3.线段树</h2>

<p>线段树与树状数组都是用于解决区间问题的数据结构，时间复杂度一样，但是线段树更清晰易懂，代码长度更长，功能更强大。</p>

<p><a href="https://www.luogu.com.cn/problem/P3372">P3372 【模板】线段树 1 - 洛谷</a></p>

<h3 id="线段树模板">线段树模板</h3>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">1e5</span><span class="o">+</span><span class="mi">10</span><span class="p">;</span>
<span class="n">ll</span> <span class="n">tree</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">],</span><span class="n">tag</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">];</span>
<span class="n">ll</span> <span class="nf">ls</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="k">return</span> <span class="n">p</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">;}</span><span class="c1">//左儿子,p*2</span>
<span class="n">ll</span> <span class="n">rs</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="k">return</span> <span class="n">p</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="o">|</span><span class="mi">1</span><span class="p">;}</span><span class="c1">//右儿子,p*2+1</span>
<span class="n">ll</span> <span class="n">a</span><span class="p">[</span><span class="n">N</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="kt">void</span> <span class="n">push_up</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="c1">//从下往上传递区间值</span>
	<span class="n">tree</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">tree</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">+</span><span class="n">tree</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span><span class="c1">//求区间和</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">build</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//建树</span>
	<span class="n">tag</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">==</span><span class="n">pr</span><span class="p">){</span><span class="n">tree</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">pl</span><span class="p">];</span><span class="k">return</span><span class="p">;}</span><span class="c1">//叶子节点</span>
	<span class="kt">int</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="n">build</span><span class="p">(</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span><span class="c1">//递归左儿子</span>
	<span class="n">build</span><span class="p">(</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">);</span><span class="c1">//递归右儿子</span>
	<span class="n">push_up</span><span class="p">(</span><span class="n">p</span><span class="p">);</span><span class="c1">//往上传递区间值</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">addtag</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">,</span><span class="n">ll</span> <span class="n">d</span><span class="p">){</span><span class="c1">//标记tag,更新tree</span>
	<span class="n">tag</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span>
	<span class="n">tree</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="o">*</span><span class="p">(</span><span class="n">pr</span><span class="o">-</span><span class="n">pl</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="n">push_down</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//tag传给子树</span>
	<span class="k">if</span><span class="p">(</span><span class="n">tag</span><span class="p">[</span><span class="n">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">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
		<span class="n">addtag</span><span class="p">(</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">,</span><span class="n">tag</span><span class="p">[</span><span class="n">p</span><span class="p">]);</span>
		<span class="n">addtag</span><span class="p">(</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">,</span><span class="n">tag</span><span class="p">[</span><span class="n">p</span><span class="p">]);</span>
		<span class="n">tag</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">update</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">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">,</span><span class="n">ll</span> <span class="n">d</span><span class="p">){</span><span class="c1">//区间修改,[l,r]+d</span>
	<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="o">&lt;=</span><span class="n">pl</span><span class="o">&amp;&amp;</span><span class="n">pr</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">){</span>
		<span class="n">addtag</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">pl</span><span class="p">,</span><span class="n">pr</span><span class="p">,</span><span class="n">d</span><span class="p">);</span><span class="k">return</span> <span class="p">;</span>
	<span class="p">}</span>
	<span class="n">push_down</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">pl</span><span class="p">,</span><span class="n">pr</span><span class="p">);</span>
	<span class="n">ll</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</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">&lt;=</span><span class="n">mid</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">,</span><span class="n">d</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">r</span><span class="o">&gt;</span><span class="n">mid</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">,</span><span class="n">d</span><span class="p">);</span>
	<span class="n">push_up</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">//调用方式：query(l,r,1,1,n);</span>
<span class="n">ll</span> <span class="n">query</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">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//查询区间[l,r]的和</span>
	<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="o">&lt;=</span><span class="n">pl</span><span class="o">&amp;&amp;</span><span class="n">pr</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">)</span> <span class="k">return</span> <span class="n">tree</span><span class="p">[</span><span class="n">p</span><span class="p">];</span>
	<span class="n">push_down</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">pl</span><span class="p">,</span><span class="n">pr</span><span class="p">);</span>
	<span class="n">ll</span> <span class="n">res</span><span class="o">=</span><span class="mi">0</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">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</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">&lt;=</span><span class="n">mid</span><span class="p">)</span> <span class="n">res</span><span class="o">+=</span><span class="n">query</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">r</span><span class="o">&gt;</span><span class="n">mid</span><span class="p">)</span> <span class="n">res</span><span class="o">+=</span><span class="n">query</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">);</span>
	<span class="k">return</span> <span class="n">res</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</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">1</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="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
	<span class="n">build</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="n">n</span><span class="p">);</span>
	<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
		<span class="kt">int</span> <span class="n">flag</span><span class="p">,</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">flag</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="o">&gt;&gt;</span><span class="n">y</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">flag</span><span class="o">==</span><span class="mi">1</span><span class="p">){</span>
			<span class="n">ll</span> <span class="n">k</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">k</span><span class="p">;</span>
			<span class="n">update</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</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="n">n</span><span class="p">,</span><span class="n">k</span><span class="p">);</span>
		<span class="p">}</span><span class="k">else</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">query</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</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="n">n</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">(){</span>
<span class="c1">//	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);</span>
		<span class="n">solve</span><span class="p">();</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="区间最值">区间最值</h3>

<p><a href="https://acm.hdu.edu.cn/showproblem.php?pid=5306">Problem - 5306</a></p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">1e6</span><span class="o">+</span><span class="mi">10</span><span class="p">;</span>
<span class="n">ll</span> <span class="n">sum</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">],</span><span class="n">ma</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">],</span><span class="n">se</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">],</span><span class="n">num</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">];</span><span class="c1">//区间和,最大值,次大值,最大值个数</span>
<span class="n">ll</span> <span class="nf">ls</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="k">return</span> <span class="n">p</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">;}</span><span class="c1">//左儿子,p*2</span>
<span class="n">ll</span> <span class="n">rs</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="k">return</span> <span class="n">p</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="o">|</span><span class="mi">1</span><span class="p">;}</span><span class="c1">//右儿子,p*2+1</span>
<span class="c1">//ll a[N];</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="kt">void</span> <span class="n">push_up</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="c1">//从下往上传递区间值</span>
	<span class="n">sum</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">sum</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">+</span><span class="n">sum</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span>
	<span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">ma</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)],</span><span class="n">ma</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">ma</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">==</span><span class="n">ma</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]){</span>
		<span class="n">se</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">se</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)],</span><span class="n">se</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]);</span>
		<span class="n">num</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">num</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">+</span><span class="n">num</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span>
	<span class="p">}</span><span class="k">else</span><span class="p">{</span>
		<span class="n">se</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">se</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)],</span><span class="n">se</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]);</span>
		<span class="n">se</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">se</span><span class="p">[</span><span class="n">p</span><span class="p">],</span><span class="n">min</span><span class="p">(</span><span class="n">ma</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)],</span><span class="n">ma</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]));</span>
		<span class="n">num</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">ma</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">&gt;</span><span class="n">ma</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">?</span><span class="n">num</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">:</span><span class="n">num</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">build</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//建树</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">==</span><span class="n">pr</span><span class="p">){</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">sum</span><span class="p">[</span><span class="n">p</span><span class="p">];</span>
		<span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">sum</span><span class="p">[</span><span class="n">p</span><span class="p">];</span><span class="n">se</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=-</span><span class="mi">1</span><span class="p">;</span><span class="n">num</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
		<span class="k">return</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">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="n">build</span><span class="p">(</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span>
	<span class="n">build</span><span class="p">(</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">);</span>
	<span class="n">push_up</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">addtag</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;=</span><span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">])</span> <span class="k">return</span><span class="p">;</span>
	<span class="n">sum</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">-=</span><span class="n">num</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">*</span><span class="p">(</span><span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">-</span><span class="n">x</span><span class="p">);</span>
	<span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">x</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">pushdown</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span>
	<span class="n">addtag</span><span class="p">(</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">]);</span>
	<span class="n">addtag</span><span class="p">(</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">]);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">update</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">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">,</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;=</span><span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">])</span> <span class="k">return</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="o">&lt;=</span><span class="n">pl</span><span class="o">&amp;&amp;</span><span class="n">pr</span><span class="o">&lt;=</span><span class="n">r</span><span class="o">&amp;&amp;</span><span class="n">se</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">&lt;</span><span class="n">x</span><span class="p">){</span><span class="n">addtag</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">x</span><span class="p">);</span><span class="k">return</span> <span class="p">;}</span>
	<span class="n">pushdown</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
	<span class="n">ll</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</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">&lt;=</span><span class="n">mid</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">,</span><span class="n">x</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">r</span><span class="o">&gt;</span><span class="n">mid</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">,</span><span class="n">x</span><span class="p">);</span>
	<span class="n">push_up</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">//调用方式：query(l,r,1,1,n);</span>
<span class="kt">int</span> <span class="n">queryMax</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">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//查询区间[l,r]的和</span>
	<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="o">&lt;=</span><span class="n">pl</span><span class="o">&amp;&amp;</span><span class="n">pr</span><span class="o">&lt;=</span><span class="n">r</span><span class="p">)</span> <span class="k">return</span> <span class="n">ma</span><span class="p">[</span><span class="n">p</span><span class="p">];</span>
	<span class="n">pushdown</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
	<span class="kt">int</span> <span class="n">res</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="n">ll</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</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">&lt;=</span><span class="n">mid</span><span class="p">)</span> <span class="n">res</span><span class="o">=</span><span class="n">queryMax</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">r</span><span class="o">&gt;</span><span class="n">mid</span><span class="p">)</span> <span class="n">res</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">res</span><span class="p">,</span><span class="n">queryMax</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">));</span>
	<span class="k">return</span> <span class="n">res</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">ll</span> <span class="n">querySum</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">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">l</span><span class="o">&lt;=</span><span class="n">pl</span><span class="o">&amp;&amp;</span><span class="n">r</span><span class="o">&gt;=</span><span class="n">pr</span><span class="p">)</span> <span class="k">return</span> <span class="n">sum</span><span class="p">[</span><span class="n">p</span><span class="p">];</span>
	<span class="n">pushdown</span><span class="p">(</span><span class="n">p</span><span class="p">);</span>
	<span class="n">ll</span> <span class="n">res</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="n">ll</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</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">&lt;=</span><span class="n">mid</span><span class="p">)</span> <span class="n">res</span><span class="o">+=</span><span class="n">querySum</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span>
	<span class="k">if</span><span class="p">(</span><span class="n">r</span><span class="o">&gt;</span><span class="n">mid</span><span class="p">)</span> <span class="n">res</span><span class="o">+=</span><span class="n">querySum</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">);</span>
	<span class="k">return</span> <span class="n">res</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">;</span>
	<span class="n">build</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="n">n</span><span class="p">);</span>
	<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
		<span class="kt">int</span> <span class="n">q</span><span class="p">,</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">x</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">q</span><span class="o">&gt;&gt;</span><span class="n">l</span><span class="o">&gt;&gt;</span><span class="n">r</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">q</span><span class="o">==</span><span class="mi">0</span><span class="p">){</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="p">;</span><span class="n">update</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</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="n">n</span><span class="p">,</span><span class="n">x</span><span class="p">);}</span>
		<span class="k">if</span><span class="p">(</span><span class="n">q</span><span class="o">==</span><span class="mi">1</span><span class="p">){</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">queryMax</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</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="n">n</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;}</span>
		<span class="k">if</span><span class="p">(</span><span class="n">q</span><span class="o">==</span><span class="mi">2</span><span class="p">){</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">querySum</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</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="n">n</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;}</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="n">ios</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="n">cout</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
	<span class="kt">int</span> <span class="n">T</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">T</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">T</span><span class="o">--</span><span class="p">)</span>
		<span class="n">solve</span><span class="p">();</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="区间合并">区间合并</h3>

<p><a href="https://acm.hdu.edu.cn/showproblem.php?pid=1540">Problem - 1540</a></p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">5e4</span><span class="o">+</span><span class="mi">10</span><span class="p">;</span>
<span class="n">ll</span> <span class="n">tree</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">],</span><span class="n">pre</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">],</span><span class="n">suf</span><span class="p">[</span><span class="n">N</span><span class="o">*</span><span class="mi">4</span><span class="p">];</span>
<span class="n">ll</span> <span class="nf">ls</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="k">return</span> <span class="n">p</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="p">;}</span><span class="c1">//左儿子,p*2</span>
<span class="n">ll</span> <span class="n">rs</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">){</span><span class="k">return</span> <span class="n">p</span><span class="o">&lt;&lt;</span><span class="mi">1</span><span class="o">|</span><span class="mi">1</span><span class="p">;}</span><span class="c1">//右儿子,p*2+1</span>
<span class="kt">int</span> <span class="n">history</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="c1">//记录村庄被毁历史</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="kt">void</span> <span class="n">push_up</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">len</span><span class="p">){</span>
	<span class="n">pre</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">pre</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span><span class="c1">//父节点接收子节点的前缀信息</span>
	<span class="n">suf</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">suf</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pre</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">==</span><span class="p">(</span><span class="n">len</span><span class="o">-</span><span class="p">(</span><span class="n">len</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">)))</span> <span class="n">pre</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">pre</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">+</span><span class="n">pre</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span><span class="c1">//左儿子都是1</span>
	<span class="k">if</span><span class="p">(</span><span class="n">suf</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">==</span><span class="p">(</span><span class="n">len</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">))</span> <span class="n">suf</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">suf</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">+</span><span class="n">suf</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span><span class="c1">//右儿子都是1</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">build</span><span class="p">(</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//建树</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">==</span><span class="n">pr</span><span class="p">){</span>
		<span class="n">tree</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">pre</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">suf</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
		<span class="k">return</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">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="n">build</span><span class="p">(</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span>
	<span class="n">build</span><span class="p">(</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">);</span>
	<span class="n">push_up</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">pr</span><span class="o">-</span><span class="n">pl</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="n">update</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">c</span><span class="p">,</span><span class="kt">int</span> <span class="n">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">==</span><span class="n">pr</span><span class="p">){</span><span class="n">tree</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">suf</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">pre</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">=</span><span class="n">c</span><span class="p">;</span><span class="k">return</span> <span class="p">;}</span><span class="c1">//更新叶子节点</span>
	<span class="kt">int</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">&lt;=</span><span class="n">mid</span><span class="p">)</span> <span class="n">update</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">c</span><span class="p">,</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">);</span>
	<span class="k">else</span> <span class="n">update</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">c</span><span class="p">,</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">);</span>
	<span class="n">push_up</span><span class="p">(</span><span class="n">p</span><span class="p">,</span><span class="n">pr</span><span class="o">-</span><span class="n">pl</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">query</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">p</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//查询区间[l,r]的和</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">==</span><span class="n">pr</span><span class="p">)</span> <span class="k">return</span> <span class="n">tree</span><span class="p">[</span><span class="n">p</span><span class="p">];</span>
	<span class="n">ll</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">&lt;=</span><span class="n">mid</span><span class="p">){</span>
		<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">+</span><span class="n">suf</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">&gt;</span><span class="n">mid</span><span class="p">)</span> <span class="k">return</span> <span class="n">suf</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">+</span><span class="n">pre</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span>
		<span class="k">else</span> <span class="k">return</span> <span class="n">query</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">),</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</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">mid</span><span class="o">+</span><span class="n">pre</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">&gt;=</span><span class="n">x</span><span class="p">)</span> <span class="k">return</span> <span class="n">pre</span><span class="p">[</span><span class="n">rs</span><span class="p">(</span><span class="n">p</span><span class="p">)]</span><span class="o">+</span><span class="n">suf</span><span class="p">[</span><span class="n">ls</span><span class="p">(</span><span class="n">p</span><span class="p">)];</span>
		<span class="k">else</span> <span class="k">return</span> <span class="n">query</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">rs</span><span class="p">(</span><span class="n">p</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">pr</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="kt">int</span> <span class="n">tot</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">x</span><span class="p">;</span>
	<span class="n">build</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="n">n</span><span class="p">);</span>
	<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
		<span class="kt">char</span> <span class="n">op</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">op</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">op</span><span class="o">==</span><span class="sc">'Q'</span><span class="p">){</span>
			<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="p">;</span>
			<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">query</span><span class="p">(</span><span class="n">x</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="n">n</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
		<span class="p">}</span><span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">op</span><span class="o">==</span><span class="sc">'D'</span><span class="p">){</span>
			<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="p">;</span><span class="n">history</span><span class="p">[</span><span class="o">++</span><span class="n">tot</span><span class="p">]</span><span class="o">=</span><span class="n">x</span><span class="p">;</span>
			<span class="n">update</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi">0</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="n">n</span><span class="p">);</span>
		<span class="p">}</span><span class="k">else</span><span class="p">{</span>
			<span class="n">x</span><span class="o">=</span><span class="n">history</span><span class="p">[</span><span class="n">tot</span><span class="o">--</span><span class="p">];</span>
			<span class="n">update</span><span class="p">(</span><span class="n">x</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="mi">1</span><span class="p">,</span><span class="n">n</span><span class="p">);</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="k">while</span><span class="p">(</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">)</span>
		<span class="n">solve</span><span class="p">();</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="扫描线">扫描线</h3>

<p>扫描线是线段树的一种经典运用，能解决矩形面积并、矩形周长并、多边形面积等几何问题。</p>

<h3 id="二维线段树树套树">二维线段树（树套树）</h3>

<h2 id="4-可持久化线段树主席树">4. 可持久化线段树（主席树）</h2>

<p><a href="https://www.luogu.com.cn/problem/P3834">P3834 【模板】可持久化线段树 2 - 洛谷</a></p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">2e5</span><span class="o">+</span><span class="mi">10</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">cnt</span><span class="p">,</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">b</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">root</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="c1">//a为原数组,b为离散化数组,root为第i颗树根节点编号</span>
<span class="k">struct</span> <span class="nc">nod</span><span class="p">{</span>
	<span class="kt">int</span> <span class="n">L</span><span class="p">,</span><span class="n">R</span><span class="p">,</span><span class="n">sum</span><span class="p">;</span><span class="c1">//L左儿子,R右儿子,sum为节点i的权值</span>
<span class="p">}</span><span class="n">tree</span><span class="p">[</span><span class="n">N</span><span class="o">&lt;&lt;</span><span class="mi">5</span><span class="p">];</span><span class="c1">//32*N差不多够用</span>
<span class="kt">int</span> <span class="n">build</span><span class="p">(</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">){</span><span class="c1">//初始化一颗空树，可以省略</span>
	<span class="kt">int</span> <span class="n">rt</span><span class="o">=++</span><span class="n">cnt</span><span class="p">;</span><span class="c1">//当前节点编号</span>
	<span class="n">tree</span><span class="p">[</span><span class="n">rt</span><span class="p">].</span><span class="n">sum</span><span class="o">=</span><span class="mi">0</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">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">&lt;</span><span class="n">pr</span><span class="p">){</span>
		<span class="n">tree</span><span class="p">[</span><span class="n">rt</span><span class="p">].</span><span class="n">L</span><span class="o">=</span><span class="n">build</span><span class="p">(</span><span class="n">pl</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">rt</span><span class="p">].</span><span class="n">R</span><span class="o">=</span><span class="n">build</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">pr</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">rt</span><span class="p">;</span><span class="c1">//返回当前节点的编号</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">update</span><span class="p">(</span><span class="kt">int</span> <span class="n">pre</span><span class="p">,</span><span class="kt">int</span> <span class="n">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">,</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span><span class="c1">//建立新线段树</span>
	<span class="kt">int</span> <span class="n">rt</span><span class="o">=++</span><span class="n">cnt</span><span class="p">;;</span>
	<span class="n">tree</span><span class="p">[</span><span class="n">rt</span><span class="p">].</span><span class="n">L</span><span class="o">=</span><span class="n">tree</span><span class="p">[</span><span class="n">pre</span><span class="p">].</span><span class="n">L</span><span class="p">;</span>
	<span class="n">tree</span><span class="p">[</span><span class="n">rt</span><span class="p">].</span><span class="n">R</span><span class="o">=</span><span class="n">tree</span><span class="p">[</span><span class="n">pre</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">rt</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">pre</span><span class="p">].</span><span class="n">sum</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="c1">//新加的数</span>
	<span class="kt">int</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">&lt;</span><span class="n">pr</span><span class="p">){</span><span class="c1">//从根节点向下建log2 n个节点</span>
		<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">&lt;=</span><span class="n">mid</span><span class="p">)</span><span class="c1">//x出现在左子树，修改左子树</span>
			<span class="n">tree</span><span class="p">[</span><span class="n">rt</span><span class="p">].</span><span class="n">L</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">pre</span><span class="p">].</span><span class="n">L</span><span class="p">,</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">,</span><span class="n">x</span><span class="p">);</span>
		<span class="k">else</span> <span class="c1">//x出现在右子树，修改右子树</span>
			<span class="n">tree</span><span class="p">[</span><span class="n">rt</span><span class="p">].</span><span class="n">R</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">pre</span><span class="p">].</span><span class="n">R</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">pr</span><span class="p">,</span><span class="n">x</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">rt</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">query</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</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">pl</span><span class="p">,</span><span class="kt">int</span> <span class="n">pr</span><span class="p">,</span><span class="kt">int</span> <span class="n">k</span><span class="p">){</span><span class="c1">//查询区间(u,v]中的第k小数</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pl</span><span class="o">==</span><span class="n">pr</span><span class="p">)</span> <span class="k">return</span> <span class="n">pl</span><span class="p">;</span><span class="c1">//到达叶子节点，找到第k小数</span>
	<span class="kt">int</span> <span class="n">x</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">v</span><span class="p">].</span><span class="n">L</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">u</span><span class="p">].</span><span class="n">L</span><span class="p">].</span><span class="n">sum</span><span class="p">;</span><span class="c1">//线段树相减</span>
	<span class="kt">int</span> <span class="n">mid</span><span class="o">=</span><span class="p">(</span><span class="n">pl</span><span class="o">+</span><span class="n">pr</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">1</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">x</span><span class="o">&gt;=</span><span class="n">k</span><span class="p">)</span><span class="c1">//左儿子数字&gt;=k,说明第k小数在左子树</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">u</span><span class="p">].</span><span class="n">L</span><span class="p">,</span><span class="n">tree</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">L</span><span class="p">,</span><span class="n">pl</span><span class="p">,</span><span class="n">mid</span><span class="p">,</span><span class="n">k</span><span class="p">);</span>
	<span class="k">else</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">u</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">v</span><span class="p">].</span><span class="n">R</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">pr</span><span class="p">,</span><span class="n">k</span><span class="o">-</span><span class="n">x</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</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">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</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">1</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="p">){</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
	<span class="p">}</span>
	<span class="n">sort</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">b</span><span class="o">+</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span><span class="c1">//对b排序，离散化</span>
	<span class="kt">int</span> <span class="n">size</span><span class="o">=</span><span class="n">unique</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">b</span><span class="o">+</span><span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">-</span><span class="n">b</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="c1">//size等于b中不重复元素个数</span>
	<span class="c1">//root[0]=build(1,size);</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">1</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="p">){</span>
		<span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="n">lower_bound</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">b</span><span class="o">+</span><span class="n">size</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="n">i</span><span class="p">])</span><span class="o">-</span><span class="n">b</span><span class="p">;</span>
		<span class="n">root</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">update</span><span class="p">(</span><span class="n">root</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span><span class="mi">1</span><span class="p">,</span><span class="n">size</span><span class="p">,</span><span class="n">x</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
		<span class="kt">int</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="n">k</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="o">&gt;&gt;</span><span class="n">y</span><span class="o">&gt;&gt;</span><span class="n">k</span><span class="p">;</span>
		<span class="kt">int</span> <span class="n">t</span><span class="o">=</span><span class="n">query</span><span class="p">(</span><span class="n">root</span><span class="p">[</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span><span class="n">root</span><span class="p">[</span><span class="n">y</span><span class="p">],</span><span class="mi">1</span><span class="p">,</span><span class="n">size</span><span class="p">,</span><span class="n">k</span><span class="p">);</span>
		<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">b</span><span class="p">[</span><span class="n">t</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="n">ios</span><span class="o">::</span><span class="n">sync_with_stdio</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="n">cin</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="mi">0</span><span class="p">),</span><span class="n">cout</span><span class="p">.</span><span class="n">tie</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
	<span class="n">solve</span><span class="p">();</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="5-分块与莫队算法">5. 分块与莫队算法</h2>

<p>分块就是将数列分成很多块，对涉及的块做整体性的维护操作。类似与一个多分线段树。</p>

<p>代码比树状数组和线段树简单，效率比暴力高的，时间复杂度 \(O(m \sqrt{n})\)。</p>

<ul>
  <li>块的大小（块的长度），<code class="language-plaintext highlighter-rouge">block=sqrt(n)</code></li>
  <li>块的数量，<code class="language-plaintext highlighter-rouge">t</code></li>
  <li>块的左右边界，<code class="language-plaintext highlighter-rouge">st[]</code> 和 <code class="language-plaintext highlighter-rouge">ed[]</code></li>
  <li>每个元素所属块，<code class="language-plaintext highlighter-rouge">pos[i]=(i-1)/block+1</code></li>
</ul>

<h3 id="分块定义初始化">分块定义，初始化</h3>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">block</span><span class="o">=</span><span class="n">sqrt</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">t</span><span class="o">=</span><span class="n">n</span><span class="o">/</span><span class="n">block</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="n">block</span><span class="p">)</span> <span class="n">t</span><span class="o">++</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">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">t</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
    <span class="n">st</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">block</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
    <span class="n">ed</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">i</span><span class="o">*</span><span class="n">block</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">ed</span><span class="p">[</span><span class="n">t</span><span class="p">]</span><span class="o">=</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">i</span><span class="o">=</span><span class="mi">1</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="p">)</span> <span class="n">pos</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="n">block</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
</code></pre></div></div>

<p><a href="https://www.luogu.com.cn/problem/P2801">P2801 教主的魔法 - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ll</span> <span class="n">n</span><span class="p">,</span><span class="n">m</span><span class="p">,</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">b</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">add</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="n">ll</span> <span class="n">t</span><span class="p">,</span><span class="n">st</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">ed</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">pos</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">change</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="n">ll</span> <span class="n">d</span><span class="p">){</span><span class="c1">//对[L,R]区间操作</span>
	<span class="kt">int</span> <span class="n">p</span><span class="o">=</span><span class="n">pos</span><span class="p">[</span><span class="n">L</span><span class="p">],</span><span class="n">q</span><span class="o">=</span><span class="n">pos</span><span class="p">[</span><span class="n">R</span><span class="p">];</span><span class="c1">//左右区间端点对应块</span>
	<span class="k">if</span><span class="p">(</span><span class="n">p</span><span class="o">==</span><span class="n">q</span><span class="p">){</span><span class="c1">//同一块，碎片</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">L</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">R</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span><span class="c1">//暴力操作区间</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">st</span><span class="p">[</span><span class="n">p</span><span class="p">];</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">ed</span><span class="p">[</span><span class="n">p</span><span class="p">];</span><span class="n">i</span><span class="o">++</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="o">=</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="c1">//维护a数组</span>
		<span class="n">sort</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="n">st</span><span class="p">[</span><span class="n">p</span><span class="p">],</span><span class="n">a</span><span class="o">+</span><span class="n">ed</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span><span class="k">else</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">p</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">q</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">add</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span><span class="c1">//整块操作</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">L</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">ed</span><span class="p">[</span><span class="n">p</span><span class="p">];</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span><span class="c1">//左碎片操作</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">st</span><span class="p">[</span><span class="n">p</span><span class="p">];</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">ed</span><span class="p">[</span><span class="n">p</span><span class="p">];</span><span class="n">i</span><span class="o">++</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="o">=</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="n">sort</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="n">st</span><span class="p">[</span><span class="n">p</span><span class="p">],</span><span class="n">a</span><span class="o">+</span><span class="n">ed</span><span class="p">[</span><span class="n">p</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">i</span><span class="o">=</span><span class="n">st</span><span class="p">[</span><span class="n">q</span><span class="p">];</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">R</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+=</span><span class="n">d</span><span class="p">;</span><span class="c1">//右碎片操作</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">st</span><span class="p">[</span><span class="n">q</span><span class="p">];</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">ed</span><span class="p">[</span><span class="n">q</span><span class="p">];</span><span class="n">i</span><span class="o">++</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="o">=</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="n">sort</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="n">st</span><span class="p">[</span><span class="n">q</span><span class="p">],</span><span class="n">a</span><span class="o">+</span><span class="n">ed</span><span class="p">[</span><span class="n">q</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="n">ll</span> <span class="n">query</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="n">ll</span> <span class="n">c</span><span class="p">){</span><span class="c1">//在[L,R]中查询</span>
	<span class="kt">int</span> <span class="n">p</span><span class="o">=</span><span class="n">pos</span><span class="p">[</span><span class="n">L</span><span class="p">],</span><span class="n">q</span><span class="o">=</span><span class="n">pos</span><span class="p">[</span><span class="n">R</span><span class="p">];</span><span class="c1">//区间端点对应块</span>
	<span class="n">ll</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">p</span><span class="o">==</span><span class="n">q</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">L</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">R</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="c1">//暴力操作碎片</span>
			<span class="k">if</span><span class="p">(</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+</span><span class="n">add</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">&gt;=</span><span class="n">c</span><span class="p">)</span> <span class="n">ans</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">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">p</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">q</span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="c1">//整块操作</span>
			<span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="n">lower_bound</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="n">st</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">a</span><span class="o">+</span><span class="n">ed</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">c</span><span class="o">-</span><span class="n">add</span><span class="p">[</span><span class="n">i</span><span class="p">])</span><span class="o">-</span><span class="n">a</span><span class="p">;</span>
			<span class="n">ans</span><span class="o">+=</span><span class="p">(</span><span class="n">ed</span><span class="p">[</span><span class="n">i</span><span class="p">]</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">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="n">L</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">ed</span><span class="p">[</span><span class="n">p</span><span class="p">];</span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="c1">//左碎片暴力查询</span>
			<span class="k">if</span><span class="p">(</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+</span><span class="n">add</span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="o">&gt;=</span><span class="n">c</span><span class="p">)</span> <span class="n">ans</span><span class="o">++</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">st</span><span class="p">[</span><span class="n">q</span><span class="p">];</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">R</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="c1">//右碎片暴力查询</span>
			<span class="k">if</span><span class="p">(</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+</span><span class="n">add</span><span class="p">[</span><span class="n">q</span><span class="p">]</span><span class="o">&gt;=</span><span class="n">c</span><span class="p">)</span> <span class="n">ans</span><span class="o">++</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</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">1</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="p">){</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];};</span><span class="c1">//复制数组</span>
	<span class="kt">int</span> <span class="n">block</span><span class="o">=</span><span class="n">sqrt</span><span class="p">(</span><span class="n">n</span><span class="p">);</span><span class="c1">//块大小</span>
	<span class="n">t</span><span class="o">=</span><span class="p">(</span><span class="n">n</span><span class="o">+</span><span class="n">block</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="n">block</span><span class="p">;</span><span class="c1">//块数量</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">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">t</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
		<span class="n">st</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="n">block</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="c1">//块的左端点</span>
		<span class="n">ed</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">i</span><span class="o">*</span><span class="n">block</span><span class="p">;</span><span class="c1">//块的右端点</span>
	<span class="p">}</span>
	<span class="n">ed</span><span class="p">[</span><span class="n">t</span><span class="p">]</span><span class="o">=</span><span class="n">n</span><span class="p">;</span><span class="c1">//防止最后一块越界</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">1</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="p">)</span> <span class="n">pos</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="n">block</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="c1">//元素对应块</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">1</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="p">)</span> <span class="n">sort</span><span class="p">(</span><span class="n">a</span><span class="o">+</span><span class="n">st</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">a</span><span class="o">+</span><span class="n">ed</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span><span class="c1">//块内排序</span>
	<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
		<span class="kt">char</span> <span class="n">c</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">c</span><span class="p">;</span>
		<span class="n">ll</span> <span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">w</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">l</span><span class="o">&gt;&gt;</span><span class="n">r</span><span class="o">&gt;&gt;</span><span class="n">w</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">c</span><span class="o">==</span><span class="sc">'M'</span><span class="p">)</span> <span class="n">change</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">w</span><span class="p">);</span><span class="c1">//区间操作</span>
		<span class="k">else</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">query</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">r</span><span class="p">,</span><span class="n">w</span><span class="p">)</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span><span class="c1">//区间查询</span>
	<span class="p">}</span>
	
<span class="p">}</span>
</code></pre></div></div>

<h3 id="基础莫队算法">基础莫队算法</h3>

<p>莫队算法=离线+暴力+分块</p>

<p>基础莫队算法用于不修改只查询的一类区间问题，复杂度为 \(O(n\sqrt{n})\) 。</p>

<p>一次性存储所有询问，按照查询区间 <strong>左端点所在块序号排序</strong>，块相同再按 <strong>右端点排序</strong>。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ll</span> <span class="n">n</span><span class="p">,</span><span class="n">m</span><span class="p">,</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">tmp</span><span class="p">;</span>
<span class="k">struct</span> <span class="nc">nod</span><span class="p">{</span><span class="c1">//记录查询,用来排序</span>
	<span class="kt">int</span> <span class="n">L</span><span class="p">,</span><span class="n">R</span><span class="p">,</span><span class="n">k</span><span class="p">;</span>
<span class="p">}</span><span class="n">q</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="n">ll</span> <span class="n">t</span><span class="p">,</span><span class="n">sum</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">ans</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">pos</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">bool</span> <span class="n">cmp</span><span class="p">(</span><span class="n">nod</span> <span class="n">a</span><span class="p">,</span><span class="n">nod</span> <span class="n">b</span><span class="p">){</span><span class="c1">//莫队排序</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pos</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="o">!=</span><span class="n">pos</span><span class="p">[</span><span class="n">b</span><span class="p">.</span><span class="n">L</span><span class="p">])</span> <span class="k">return</span> <span class="n">pos</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="o">&lt;</span><span class="n">pos</span><span class="p">[</span><span class="n">b</span><span class="p">.</span><span class="n">L</span><span class="p">];</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pos</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="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">R</span><span class="o">&gt;</span><span class="n">b</span><span class="p">.</span><span class="n">R</span><span class="p">;</span><span class="c1">//奇偶性优化</span>
	<span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">R</span><span class="o">&lt;</span><span class="n">b</span><span class="p">.</span><span class="n">R</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">add</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span><span class="n">sum</span><span class="p">[</span><span class="n">a</span><span class="p">[</span><span class="n">x</span><span class="p">]]</span><span class="o">++</span><span class="p">;</span><span class="k">if</span><span class="p">(</span><span class="n">sum</span><span class="p">[</span><span class="n">a</span><span class="p">[</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">tmp</span><span class="o">++</span><span class="p">;}</span>
<span class="kt">void</span> <span class="n">del</span><span class="p">(</span><span class="kt">int</span> <span class="n">x</span><span class="p">){</span><span class="n">sum</span><span class="p">[</span><span class="n">a</span><span class="p">[</span><span class="n">x</span><span class="p">]]</span><span class="o">--</span><span class="p">;</span><span class="k">if</span><span class="p">(</span><span class="n">sum</span><span class="p">[</span><span class="n">a</span><span class="p">[</span><span class="n">x</span><span class="p">]]</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span> <span class="n">tmp</span><span class="o">--</span><span class="p">;}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">block</span><span class="o">=</span><span class="n">sqrt</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">i</span><span class="o">=</span><span class="mi">1</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="p">){</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">pos</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">/</span><span class="n">block</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="c1">//记录对应块</span>
	<span class="p">}</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">m</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">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">m</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="c1">//记录查询</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">q</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">L</span><span class="o">&gt;&gt;</span><span class="n">q</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">R</span><span class="p">;</span><span class="n">q</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">k</span><span class="o">=</span><span class="n">i</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="n">sort</span><span class="p">(</span><span class="n">q</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">q</span><span class="o">+</span><span class="n">m</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">cmp</span><span class="p">);</span><span class="c1">//查询排序</span>
	<span class="kt">int</span> <span class="n">L</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">R</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="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">m</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="c1">//查询处理</span>
		<span class="k">while</span><span class="p">(</span><span class="n">L</span><span class="o">&lt;</span><span class="n">q</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">L</span><span class="p">)</span> <span class="n">del</span><span class="p">(</span><span class="n">L</span><span class="o">++</span><span class="p">);</span>
		<span class="k">while</span><span class="p">(</span><span class="n">R</span><span class="o">&gt;</span><span class="n">q</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">R</span><span class="p">)</span> <span class="n">del</span><span class="p">(</span><span class="n">R</span><span class="o">--</span><span class="p">);</span>
		<span class="k">while</span><span class="p">(</span><span class="n">L</span><span class="o">&gt;</span><span class="n">q</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">L</span><span class="p">)</span> <span class="n">add</span><span class="p">(</span><span class="o">--</span><span class="n">L</span><span class="p">);</span>
		<span class="k">while</span><span class="p">(</span><span class="n">R</span><span class="o">&lt;</span><span class="n">q</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">R</span><span class="p">)</span> <span class="n">add</span><span class="p">(</span><span class="o">++</span><span class="n">R</span><span class="p">);</span>
		<span class="n">ans</span><span class="p">[</span><span class="n">q</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">tmp</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="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">m</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">ans</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="带修改的莫队算法">带修改的莫队算法</h3>

<p>如果只是简单的单点修改，也能使用莫队算法，但是复杂度为 \(O(mn^{2/3})\)</p>

<h3 id="树上莫队">树上莫队</h3>

<p><a href="https://www.luogu.com.cn/problem/SP10707">SP10707 COT2 - Count on a tree II - 洛谷</a></p>

<p>将树转换成欧拉序变为一维数组。</p>

<h2 id="6-块状链表">6. 块状链表</h2>

<p>块状链表=分块+链表</p>

<h2 id="7-简单树上问题">7. 简单树上问题</h2>

<p>判断一个图是否为树：</p>

<ul>
  <li>找根节点：只有出边没有入边的点，只有一个，无向图任何点都可以</li>
  <li>判断环：从根DFS遍历图，每个节点只被访问一次</li>
  <li>检查联通性：判断环后，检查所有点是否都访问到</li>
  <li>时间复杂度为 \((n+m)\)</li>
</ul>

<h3 id="树的重心">树的重心</h3>

<p>删除重心这个节点后，得到的最大子树的节点数最少。</p>

<h2 id="8-lca">8. LCA</h2>

<h2 id="9-树上的分治">9. 树上的分治</h2>

<h2 id="10-树链剖分">10. 树链剖分</h2>

<h2 id="11-二叉查找树">11. 二叉查找树</h2>

<h2 id="12-替罪羊树">12. 替罪羊树</h2>

<h2 id="13-treap树">13. Treap树</h2>

<h2 id="14-fhq-treap树">14. FHQ Treap树</h2>

<h2 id="15-笛卡尔树">15. 笛卡尔树</h2>

<h2 id="16-splay树">16. Splay树</h2>

<h2 id="17-k-d树">17. K-D树</h2>

<h2 id="18-动态树与lct">18. 动态树与LCT</h2>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="algorithms" /><summary type="html"><![CDATA[《算法竞赛》第4章高级数据结构：并查集（含带权）、树状数组（单点/区间修改+查询）、线段树（区间最值/合并/扫描线）、主席树、分块与莫队、树上问题、LCA、树链剖分、Treap、Splay等。]]></summary></entry><entry><title type="html">24年CCPC郑州邀请赛VP</title><link href="https://tzf0237.github.io/posts/24%E5%B9%B4CCPC%E9%83%91%E5%B7%9E%E9%82%80%E8%AF%B7%E8%B5%9BVP/" rel="alternate" type="text/html" title="24年CCPC郑州邀请赛VP" /><published>2025-06-01T00:00:00+08:00</published><updated>2025-06-01T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/24%E5%B9%B4CCPC%E9%83%91%E5%B7%9E%E9%82%80%E8%AF%B7%E8%B5%9BVP</id><content type="html" xml:base="https://tzf0237.github.io/posts/24%E5%B9%B4CCPC%E9%83%91%E5%B7%9E%E9%82%80%E8%AF%B7%E8%B5%9BVP/"><![CDATA[<h2 id="24年ccpc郑州邀请赛暨第六届ccpc河南省赛">24年CCPC郑州邀请赛暨第六届CCPC河南省赛</h2>

<!-- more -->

<h3 id="a-once-in-my-life">A. Once In My Life</h3>

<p><strong>题意：</strong>一个数的数位包含 1~9 并且至少两个数位是 d 的十进制正整数都是幸运数。给出 d 和一个正整数 n，输出一个 k 使得 n*k 是幸运数。</p>

<p><strong>题解：</strong>我们需要先构造出乘积。1234567890 满足包含 1~9 的条件，再加上 d 满足幸运数。为了不影响这个数幸运数的性质，我们可以在这个数后面添加几位使得这个数变成 n 的倍数。先在 123456789d 后面添加 n 位数个 0，加上 <code class="language-plaintext highlighter-rouge">n-c%n</code> 使这个数变成 n 的倍数，除以 n 即可得到 k。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
    <span class="n">ll</span> <span class="n">n</span><span class="p">,</span><span class="n">d</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">d</span><span class="p">;</span>
    <span class="n">ll</span> <span class="n">len</span><span class="o">=</span><span class="n">to_string</span><span class="p">(</span><span class="n">n</span><span class="p">).</span><span class="n">size</span><span class="p">();</span><span class="c1">//求n的位数</span>
    <span class="n">ll</span> <span class="n">c</span><span class="o">=</span><span class="mi">1234567890ll</span><span class="o">+</span><span class="n">d</span><span class="p">;</span><span class="c1">//构造幸运数</span>
    <span class="n">c</span><span class="o">=</span><span class="n">c</span><span class="o">*</span><span class="n">pow</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span><span class="n">len</span><span class="p">);</span><span class="c1">//后面添0</span>
    <span class="n">c</span><span class="o">+=</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="n">c</span><span class="o">%</span><span class="n">n</span><span class="p">);</span><span class="c1">//使这个数变成n的倍数</span>
    <span class="n">ll</span> <span class="n">ans</span><span class="o">=</span><span class="n">c</span><span class="o">/</span><span class="n">n</span><span class="p">;</span>
    <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">ans</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="c-中二病也要打比赛">C. 中二病也要打比赛</h3>

<p><strong>题意：</strong>给定一个序列 A，元素范围在 1~n 内。使用某个映射将序列 A 变为一个单调不降的序列。代价为 \(f(x)≠x\) 的数量。求最小代价。</p>

<p><strong>题解：</strong>如果某两个数值相等，则这两数之间所有的数也全部相等。可以仅保留某个数的第一次出现和最后一次出现。问题就转化为每一段取一个数，求 LIS。将每一段中的数降序排列，求出最长严格上升子序列后即得。用数组总长度减去 LIS 长度就是答案。</p>

<h3 id="k-树上问题">K. 树上问题</h3>

<p><strong>题意：</strong>有一颗 n 个节点组成的无根树，每个节点有正整数点权。一个节点是美丽节点的充要条件为以这个节点做根所有节点的点权不小于其父亲节点的一半。有多少个美丽节点？</p>

<p><strong>题解：</strong>先以任意结点做根，构成一棵树。对于相连的结点如 u 和 v，以 u 和 v 为根时，只有 u-v 这条边的方向发生变化。因此给 \(ans_u\) 减去 \(v→u\) 的贡献，加上 \(u→v\) 的贡献，就得到了 \(ans_v\)。采用换根 DP。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">dfs1</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span><span class="kt">int</span> <span class="n">fa</span><span class="p">){</span>
    <span class="kt">int</span> <span class="n">sum</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="mi">0</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;</span><span class="n">vt</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
        <span class="kt">int</span> <span class="n">v</span><span class="o">=</span><span class="n">vt</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="p">(</span><span class="n">v</span><span class="o">==</span><span class="n">fa</span><span class="p">)</span> <span class="k">continue</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">u</span><span class="p">);</span>
        <span class="n">sum</span><span class="o">+=</span><span class="n">cnt</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">a</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">*</span><span class="mi">2</span><span class="o">&lt;</span><span class="n">a</span><span class="p">[</span><span class="n">u</span><span class="p">]);</span>
    <span class="p">}</span>
    <span class="n">cnt</span><span class="p">[</span><span class="n">u</span><span class="p">]</span><span class="o">=</span><span class="n">sum</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">dfs2</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span><span class="kt">int</span> <span class="n">fa</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="n">vt</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
        <span class="kt">int</span> <span class="n">v</span><span class="o">=</span><span class="n">vt</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="p">(</span><span class="n">v</span><span class="o">==</span><span class="n">fa</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
        <span class="n">ans</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">=</span><span class="n">ans</span><span class="p">[</span><span class="n">u</span><span class="p">]</span><span class="o">-</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">v</span><span class="p">]</span><span class="o">*</span><span class="mi">2</span><span class="o">&lt;</span><span class="n">a</span><span class="p">[</span><span class="n">u</span><span class="p">])</span><span class="o">+</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">u</span><span class="p">]</span><span class="o">*</span><span class="mi">2</span><span class="o">&lt;</span><span class="n">a</span><span class="p">[</span><span class="n">v</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">u</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="l-toxel-与-pcpc-ii">L. Toxel 与 PCPC II</h3>

<p><strong>题意：</strong>有 n 行代码和 m 行出现 bug，可以选择一个 i，从第一行执行到 i 行，需要 i 秒，并且修复这 i 行内的所有 bug，需要额外时间即 bug 数量的 4 次方。问最少时间修复所有 bug。</p>

<p><strong>题解：</strong>简单 DP。状态：\(dp[i]\) 表示修复前 i 个 bug 所需的最少时间。转移方程：\(dp[i]=min_{1≤j≤i}(dp[j]+a_i+(i-j)^4)\)。</p>

<p>时间复杂度为 \(O(m^2)\)，会 TLE。优化：如果我们多运行一次代码，最大花费为 2e5，但是 \(38^4-37^4&gt;2e5\)，这意味着选了 38 个 bug 不如先选一个 bug 再选 37 个 bug。所以只需向下枚举四五十行即可，时间复杂度 \(O(40m)\)。</p>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="ACM-ICPC" /><category term="algorithms" /><summary type="html"><![CDATA[24年CCPC郑州邀请赛暨第六届CCPC河南省赛补题：A. Once In My Life、C. 中二病也要打比赛、K. 树上问题、L. Toxel 与 PCPC II。]]></summary></entry><entry><title type="html">优先队列重载</title><link href="https://tzf0237.github.io/posts/%E4%BC%98%E5%85%88%E9%98%9F%E5%88%97%E9%87%8D%E8%BD%BD/" rel="alternate" type="text/html" title="优先队列重载" /><published>2025-05-31T00:00:00+08:00</published><updated>2025-05-31T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/%E4%BC%98%E5%85%88%E9%98%9F%E5%88%97%E9%87%8D%E8%BD%BD</id><content type="html" xml:base="https://tzf0237.github.io/posts/%E4%BC%98%E5%85%88%E9%98%9F%E5%88%97%E9%87%8D%E8%BD%BD/"><![CDATA[<h2 id="优先队列重载">优先队列重载</h2>

<!-- more -->

<p>STL 中对优先队列进行封装，我们可以直接定义使用。插入与取出的时间复杂度为 \(O(log_2n)\)。</p>

<p><strong>普通定义：</strong></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">priority_queue</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">pq</span><span class="p">;</span>
</code></pre></div></div>

<p><strong>调用系统排序定义：</strong></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">priority_queue</span><span class="o">&lt;</span><span class="kt">int</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="p">,</span><span class="n">greater</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="n">pq</span><span class="p">;</span>
<span class="n">priority_queue</span><span class="o">&lt;</span><span class="kt">int</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="p">,</span><span class="n">less</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;</span> <span class="o">&gt;</span> <span class="n">pq</span><span class="p">;</span>
</code></pre></div></div>

<p><strong>自定义结构体定义：</strong></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">nod</span><span class="p">{</span>
    <span class="kt">int</span> <span class="n">num</span><span class="p">;</span>
    <span class="k">friend</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">&lt;</span> <span class="p">(</span><span class="n">nod</span> <span class="n">a</span><span class="p">,</span><span class="n">nod</span> <span class="n">b</span><span class="p">){</span>
        <span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">num</span><span class="o">&gt;</span><span class="n">b</span><span class="p">.</span><span class="n">num</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">nod</span><span class="o">&gt;</span> <span class="n">pq</span><span class="p">;</span>
</code></pre></div></div>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="algorithms" /><summary type="html"><![CDATA[STL优先队列的普通定义、系统排序定义（greater/less）及自定义结构体重载运算符的用法。]]></summary></entry><entry><title type="html">2024年ICPC贵州省赛题解</title><link href="https://tzf0237.github.io/posts/24%E8%B4%B5%E5%B7%9E%E7%9C%81%E8%B5%9B%E9%A2%98%E8%A7%A3/" rel="alternate" type="text/html" title="2024年ICPC贵州省赛题解" /><published>2025-05-30T00:00:00+08:00</published><updated>2025-05-30T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/24%E8%B4%B5%E5%B7%9E%E7%9C%81%E8%B5%9B%E9%A2%98%E8%A7%A3</id><content type="html" xml:base="https://tzf0237.github.io/posts/24%E8%B4%B5%E5%B7%9E%E7%9C%81%E8%B5%9B%E9%A2%98%E8%A7%A3/"><![CDATA[<h2 id="2024贵州省赛题解">2024贵州省赛题解</h2>

<!-- more -->

<h3 id="a-破解住宿信息">A. 破解住宿信息</h3>

<p>简单判断。输入字符串含空格，整行输入。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">string</span> <span class="n">s</span><span class="p">;</span>
<span class="n">getline</span><span class="p">(</span><span class="n">cin</span><span class="p">,</span><span class="n">s</span><span class="p">);</span>
<span class="kt">int</span> <span class="n">sum</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">x</span><span class="p">;</span>
<span class="n">x</span><span class="o">=</span><span class="n">s</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">"GZU"</span><span class="p">);</span>
<span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="o">!=-</span><span class="mi">1</span><span class="p">){</span>
    <span class="n">sum</span><span class="o">++</span><span class="p">;</span>
    <span class="n">x</span><span class="o">=</span><span class="n">s</span><span class="p">.</span><span class="n">find</span><span class="p">(</span><span class="s">"GZU"</span><span class="p">,</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">if</span><span class="p">(</span><span class="n">sum</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"yezhulin"</span><span class="p">;</span>
<span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">sum</span><span class="o">%</span><span class="mi">2</span><span class="p">)</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"heshangpo"</span><span class="p">;</span>
<span class="k">else</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"qingrenpo"</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="b-小帅的车费">B. 小帅的车费</h3>

<p>分层图最短路模板题。直接建立 k+1 层图，层与层间依次用打折后的边权相连。跑一遍 Dijkstra 即可。</p>

<h3 id="c-细胞的合并">C. 细胞的合并</h3>

<p>数据量为 \(2000^2=4e6\)，暴力枚举细胞是否相连，相连就并查集加入。</p>

<h3 id="d-还在排队的人">D. 还在排队的人</h3>

<p>双端队列的模拟，使用 <code class="language-plaintext highlighter-rouge">deque</code> 直接秒。</p>

<h3 id="e-打怪兽">E. 打怪兽</h3>

<p>二分 + 尺取法。二分 damage，在 check 函数中计算所需最少次数。维护一段数组存放造成伤害的下标，如果某造成伤害下标对当前第 i 处造成不了伤害，左指针前移。</p>

<h3 id="f-关灯">F. 关灯</h3>

<p>暴力枚举最大长度 len。每次操作使 \([i,i+k-1]\) 内的数都减一，利用差分数组实现。需要考虑负数取模的影响。</p>

<h3 id="g-小帅的骰子">G. 小帅的骰子</h3>

<p>模拟两次投出来的结果，然后判断满足条件的可能结果有多少种，求最大公因数约分即可。</p>

<h3 id="h-粉刷匠小帅">H. 粉刷匠小帅</h3>

<p>线段树，待学习。</p>

<h3 id="i-寻找宝藏数">I. 寻找宝藏数</h3>

<p>数位 DP。先利用质数筛预处理出所有 4 位合数。设 \(dp[N][i][j][k]\) 表示最高位为 i、次高位为 j、第三位为 k 的 N 位宝藏数的个数。时间复杂度 \(O(n*10^4)\)。</p>

<h3 id="j-数字游戏">J. 数字游戏</h3>

<p>设删掉一个数字及其生成的所有数字所需要的次数的奇偶性为 f[x]。通过打表观察到只有 f[1]=1，其余为 0。所以只需要统计数字 1 的个数的奇偶性即可。</p>

<h3 id="k-最好的好朋友活动">K. 最好的好朋友活动</h3>

<p>若 a[i] 是负数，则在 b 数组中找一个最小的负数，负负得正则乘积最大；反之正数找最大正数。时间复杂度 \(O(max(n,m))\)。</p>

<h3 id="l-gzu的建筑">L. GZU的建筑</h3>

<p>字典树 + 树上启发式合并（dsu on tree），待学习。</p>

<h3 id="m-递增的鸭鸭">M. 递增的鸭鸭</h3>

<p>离散化 + DP + 组合计数。DP 状态：\(dp[j]\) = 前 j 只鸭子的合法方案数。遍历所有离散段，在每个段上使用隔板法（C(n+r-l, n)）更新状态。</p>

<h3 id="n-乐乐爱购物">N. 乐乐爱购物</h3>

<p>莫比乌斯反演，待学习。</p>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="algorithms" /><category term="ACM-ICPC" /><summary type="html"><![CDATA[2024年ICPC贵州省赛完整题解：A破解住宿信息、B分层图最短路、C并查集、D双端队列、E二分+尺取法、F差分数组、G概率模拟、I数位DP、J异或博弈、K贪心、M离散化DP。]]></summary></entry><entry><title type="html">近期DP题目</title><link href="https://tzf0237.github.io/posts/%E8%BF%91%E6%9C%9FDP%E9%A2%98%E7%9B%AE/" rel="alternate" type="text/html" title="近期DP题目" /><published>2025-05-26T00:00:00+08:00</published><updated>2025-05-26T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/%E8%BF%91%E6%9C%9FDP%E9%A2%98%E7%9B%AE</id><content type="html" xml:base="https://tzf0237.github.io/posts/%E8%BF%91%E6%9C%9FDP%E9%A2%98%E7%9B%AE/"><![CDATA[<h2 id="几道dp题目">几道DP题目</h2>

<p>牛客练习赛 139C，25 武汉邀请赛 FG 等</p>

<!-- more -->

<h3 id="c-大卫的密码牛客练习赛139">C-大卫的密码（牛客练习赛139）</h3>

<p><strong>题意：</strong>给定一个 \(n\times m\) 的网格图，从 (s,1) 出发，每次可以向右或者向下移动，当光标移动到最后一行的某个格子时，继续向下移动则会到达 (1,i) 格子。需要移动光标到达 (t,m)，求最大价值和。</p>

<p><strong>题解：</strong>二维 DP+限制。定义状态 \(dp[i][j]\) 表示在 (i,j) 位置时的最大价值和。因为纵向可以走到底然后从上面走下来，从左往右一列一列转移。</p>

<p>设 \(s_n=\sum_{i=1}^n a[i][j]\)，则转移方程为：
\(dp_{i,j} \leftarrow \max_{k} \left( dp_{k,j-1} +
\begin{cases}
s_i - s_{k-1} &amp; \text{if } ~k &lt; i \\
s_n - (s_{k-1} - s_i) &amp; \text{if } ~k &gt; i
\end{cases}
\right)\)</p>

<p>DP 数组可以滚动优化。</p>

<h3 id="p12593-沉石鱼惊旋">P12593 沉石鱼惊旋</h3>

<p><strong>题意：</strong>有一张 n 个点 m 条边的简单无向带权连通图。进行 n 次操作，每次选择一个仍未被删除的点 u，删除点 u 和当前与 u 相连的所有边。总代价是这 n 次操作的代价和，求最小总代价。</p>

<p><strong>题解：</strong>状压 DP。定义状态 \(f[S]\) 为已经删过点的集合为 S 时所能取得的最小代价。时间复杂度 \(O(2^n n^2)\)，可通过 n≤16 的范围。</p>

<h3 id="p12597-穿睡衣军训">P12597 穿睡衣军训</h3>

<p><strong>题意：</strong>给定两个字符串 s,t，求出一个字符串 x 满足：x 是 s 的子串、x 是 t 的子序列、长度最长、字典序最小。</p>

<p><strong>题解：</strong>\(O(n^2)\) 枚举子串，判断子序列可以继承上一段的结果，优化到 \(O(Tn^2 \log m)\)。</p>

<h3 id="2025武汉邀请赛-f-背包">2025武汉邀请赛-F 背包</h3>

<p><strong>题意：</strong>有 n 组物品，第 i 组有 \(a_i\) 个，每个重量为 \(2^{b_i}\)。m 个背包，每个承重为 k。求最小的 k 使所有物品都能放入。</p>

<h3 id="2025武汉邀请赛-g-路径求和问题">2025武汉邀请赛-G 路径求和问题</h3>

<p><strong>题意：</strong>有一个 n×m 的网格，从 (1,1) 走到 (n,m)，只能往下或往右。一条路径的价值定义为路径上不同整数的数量。对于所有可能路径，求价值之和。</p>

<p><strong>题解：</strong>使用组合计数 + 容斥。对于出现次数较少的数使用 func1（暴力 DP），出现次数较多的数使用 func2（整体容斥），块大小阈值取 \(\sqrt{nm}\)。</p>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="algorithms" /><summary type="html"><![CDATA[几道DP题目：牛客练习赛139C（二维DP+限制）、洛谷P12593（状压DP）、P12597（枚举子串+DP判断子序列）、2025武汉邀请赛F（背包）和G（路径求和）。]]></summary></entry><entry><title type="html">算法竞赛DP ——《算法竞赛》第5章 动态规划</title><link href="https://tzf0237.github.io/posts/%E7%AE%97%E6%B3%95%E7%AB%9E%E8%B5%9BDP/" rel="alternate" type="text/html" title="算法竞赛DP ——《算法竞赛》第5章 动态规划" /><published>2025-05-22T00:00:00+08:00</published><updated>2025-05-22T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/%E7%AE%97%E6%B3%95%E7%AB%9E%E8%B5%9BDP</id><content type="html" xml:base="https://tzf0237.github.io/posts/%E7%AE%97%E6%B3%95%E7%AB%9E%E8%B5%9BDP/"><![CDATA[<h1 id="算法竞赛第-5-章-动态规划">《算法竞赛》第 5 章 动态规划</h1>

<!-- more -->

<h2 id="1-dp概念和编程方法">1. DP概念和编程方法</h2>

<h3 id="11-dp的概念">1.1 DP的概念</h3>

<p>DP是求解多阶段决策问题最优化的一种算法思想。</p>

<p>解决的问题具有两个特征。</p>

<p><strong>重叠子问题</strong>：子问题会重叠，即多个不同问题会用到相同子问题</p>

<p><strong>最优子结构</strong>：大问题的最优解由小问题最优解得来，但小问题最优解求解过程与大问题无关。</p>

<h3 id="12-dp的两种编程方法">1.2 DP的两种编程方法</h3>

<p>自顶向下（先大问题，再小问题），即递归记忆化搜索。</p>

<p>自底向上（先小问题，再大问题），即递推。</p>

<p>自底向上的优点是编码更直接。</p>

<h3 id="13-dp的设计和实现">1.3 DP的设计和实现</h3>

<p>刷题。</p>

<h3 id="14-滚动数组">1.4 滚动数组</h3>

<p>滚动数组可以减少空间复杂度，但也会损失DP数组存储的信息。</p>

<p>如 01 背包使用滚动数组优化后，无法输出具体方案。</p>

<p>有的DP状态已经是最小空间复杂度，无法再使用滚动数组优化。</p>

<p>两种实现滚动数组的方式。</p>

<p><strong>交替滚动</strong>：用 \(dp[0][]\) 和 \(dp[1][]\) 交替滚动</p>

<p>例如01背包</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">now</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">old</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">i</span><span class="o">=</span><span class="mi">1</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="p">){</span>
    <span class="n">swap</span><span class="p">(</span><span class="n">now</span><span class="p">,</span><span class="n">old</span><span class="p">);</span><span class="c1">//交替滚动</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="n">c</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">){</span>
        <span class="k">if</span><span class="p">(</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&gt;</span><span class="n">j</span><span class="p">)</span> <span class="n">dp</span><span class="p">[</span><span class="n">now</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">dp</span><span class="p">[</span><span class="n">old</span><span class="p">][</span><span class="n">j</span><span class="p">];</span>
        <span class="k">else</span> <span class="n">dp</span><span class="p">[</span><span class="n">now</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">old</span><span class="p">][</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">old</span><span class="p">][</span><span class="n">j</span><span class="o">-</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">+</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p><strong>自我滚动</strong>：自我覆盖</p>

<p>例如01背包</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">1</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="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">c</span><span class="p">;</span><span class="n">j</span><span class="o">&gt;=</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">j</span><span class="o">--</span><span class="p">){</span>
        <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">+</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="2-线性dp">2. 线性DP</h2>

<p>一些经典线性DP问题。</p>

<h4 id="1-分组背包">1. 分组背包</h4>

<p>有一些物品，分为 n 组，第 i 组第 k 个物品体积为 \(c[i][k]\)，价值为 \(w[i][k]\)。每组最多选一个，给定容量为 C 的背包，如何选使总价值最大。</p>

<p><a href="https://www.luogu.com.cn/problem/P1757">P1757 通天之分组背包 - 洛谷</a></p>

<p>状态：\(dp[i][j]\)，前 i 组物品装容量 j 的背包获得最大价值。</p>

<p>状态转移方程：\(dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i][k]]+w[i][k])\)</p>

<p>对于 \(dp[i][j]\) 只使用到 \(dp[i-1][]\)，所以可使用滚动数组优化。</p>

<p>即状态转移方程：\(dp[j]=max(dp[j],dp[j-c[i][k]]+w[i][k])\)</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">zu</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="c1">//组数</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">m</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="p">)</span><span class="c1">//体积</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">1</span><span class="p">;</span><span class="n">k</span><span class="o">&lt;=</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="o">++</span><span class="p">)</span><span class="c1">//第i组物品数</span>
            <span class="k">if</span><span class="p">(</span><span class="n">j</span><span class="o">&gt;=</span><span class="n">v</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="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">v</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">w</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]);</span>
</code></pre></div></div>

<h4 id="2-多重背包">2. 多重背包</h4>

<p>给定 n 种物品和一个背包，第 i 种物品的体积为 \(c_i\)，价值为 \(w_i\)，并且有 \(m_i\) 个，背包总容量为 C。使背包总价值最大。</p>

<p><a href="https://www.luogu.com.cn/problem/P1776">P1776 宝物筛选 - 洛谷</a></p>

<p>4 种解法。</p>

<p>第一种，转换为01背包，把每种的背包都看作单独物品。</p>

<p>时间复杂度为\(O(C\sum _{i=1}^n m_i)\)。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">C</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">1</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="p">){</span>
    <span class="kt">int</span> <span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="o">&gt;&gt;</span><span class="n">b</span><span class="o">&gt;&gt;</span><span class="n">c</span><span class="p">;</span>
    <span class="k">while</span><span class="p">(</span><span class="n">c</span><span class="o">--</span><span class="p">)</span> <span class="n">w</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">v</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="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="n">w</span><span class="p">.</span><span class="n">size</span><span class="p">();</span><span class="n">i</span><span class="o">++</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">C</span><span class="p">;</span><span class="n">j</span><span class="o">&gt;=</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">j</span><span class="o">--</span><span class="p">){</span>
        <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">v</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">+</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="n">C</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
</code></pre></div></div>

<p>第二种，转换为分组背包，时间复杂度也为\(O(C\sum _{i=1}^n m_i)\)。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">C</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">1</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="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&gt;&gt;</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">[</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">i</span><span class="o">=</span><span class="mi">1</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="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">C</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="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">1</span><span class="p">;</span><span class="n">k</span><span class="o">&lt;=</span><span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">k</span><span class="o">++</span><span class="p">){</span>
            <span class="k">if</span><span class="p">(</span><span class="n">k</span><span class="o">*</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&gt;</span><span class="n">j</span><span class="p">)</span> <span class="k">break</span><span class="p">;</span>
            <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">k</span><span class="o">*</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">+</span><span class="n">k</span><span class="o">*</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="n">C</span><span class="p">];</span>
</code></pre></div></div>

<p>第三种，二进制拆分优化</p>

<p>若第 i 种物品有 m 个，放进背包的方案有 m+1 种，组合出这 m+1 种并不需要m个物品。根据二进制的原理，任何一个十进制数 X 都可以使用 2 的不同幂次方相加得到，这些幂次方个数只有 \(log_2 X\) 个。所以第 i 种物品的 m 个物品，可以使用 \(log_2 m\) 个表示。复杂度从 \(O(C \sum_{i=1}^n m_i)\) 优化到 \(O(C \sum_{i=1}^n log_2 ~ m_i)\) 。</p>

<p>注意拆分的具体实现，不能全部拆成 2 的倍数，而是先按 2 的幂次方从小到大拆，最后一个小于或等于最大倍数的余数。这样能保证拆出的数相加在 \([1,m_i]\) 范围内，不会大于 \(m_i\) 。</p>

<p>例如，\(m_i=25\)，把它拆成 \(1+2+4+8+10\)，最后余数 10，可保证这拆分数组合不会超过 25。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">C</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="kt">int</span> <span class="n">w</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">c</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">m</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">new_n</span><span class="p">;</span><span class="c1">//二进制拆分后的新物品总数量</span>
<span class="kt">int</span> <span class="n">new_w</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">new_c</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">new_m</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="c1">//二进制拆分后的新物品</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">C</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">1</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="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&gt;&gt;</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">[</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">i</span><span class="o">=</span><span class="mi">1</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="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">1</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">i</span><span class="p">];</span><span class="n">j</span><span class="o">&lt;&lt;=</span><span class="mi">1</span><span class="p">){</span><span class="c1">//二进制枚举</span>
			<span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">-=</span><span class="n">j</span><span class="p">;</span><span class="c1">//减去已拆分的</span>
			<span class="n">new_c</span><span class="p">[</span><span class="o">++</span><span class="n">new_n</span><span class="p">]</span><span class="o">=</span><span class="n">j</span><span class="o">*</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="c1">//新物品</span>
			<span class="n">new_w</span><span class="p">[</span><span class="n">new_n</span><span class="p">]</span><span class="o">=</span><span class="n">j</span><span class="o">*</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="p">}</span>
		<span class="k">if</span><span class="p">(</span><span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">]){</span>
			<span class="n">new_c</span><span class="p">[</span><span class="o">++</span><span class="n">new_n</span><span class="p">]</span><span class="o">=</span><span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="n">c</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
			<span class="n">new_w</span><span class="p">[</span><span class="n">new_n</span><span class="p">]</span><span class="o">=</span><span class="n">m</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="n">w</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="c1">//下面是滚动数组的 01背包</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">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">new_n</span><span class="p">;</span><span class="n">i</span><span class="o">++</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">C</span><span class="p">;</span><span class="n">j</span><span class="o">&gt;=</span><span class="n">new_c</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">j</span><span class="o">--</span><span class="p">)</span>
			<span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">new_c</span><span class="p">[</span><span class="n">i</span><span class="p">]]</span><span class="o">+</span><span class="n">new_w</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="n">C</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>二进制拆分可以看作多重背包问题的标准解法，下面是最优解法。</p>

<p>第四种，单调队列优化</p>

<p>原理后续DP优化再补。时间复杂度为 \(O(nC)\) ，是最优的解法。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">C</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">ans</span><span class="p">,</span><span class="n">tmp</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">f</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">que</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">num</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">C</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">1</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="p">){</span>
		<span class="kt">int</span> <span class="n">v</span><span class="p">,</span><span class="n">w</span><span class="p">,</span><span class="n">m</span><span class="p">;</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">w</span><span class="o">&gt;&gt;</span><span class="n">v</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">v</span><span class="o">==</span><span class="mi">0</span><span class="p">){</span><span class="n">ans</span><span class="o">+=</span><span class="n">m</span><span class="o">*</span><span class="n">w</span><span class="p">;</span><span class="k">continue</span><span class="p">;}</span><span class="c1">//体积为0，避免除数为0的情况</span>
		<span class="kt">int</span> <span class="n">can_use</span><span class="o">=</span><span class="n">min</span><span class="p">(</span><span class="n">m</span><span class="p">,</span><span class="n">C</span><span class="o">/</span><span class="n">v</span><span class="p">);</span><span class="c1">//can_use表示最大可用数量</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="n">v</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">){</span><span class="c1">//枚举每一个余数</span>
			<span class="c1">//注意这要保证转移到所有可以转移点</span>
			<span class="kt">int</span> <span class="n">all</span><span class="o">=</span><span class="p">(</span><span class="n">C</span><span class="o">-</span><span class="n">j</span><span class="p">)</span><span class="o">/</span><span class="n">v</span><span class="p">,</span><span class="n">head</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span><span class="n">tail</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="c1">//找到区间内这个余数下有机会转移到的所有点</span>
			<span class="c1">//每次重置队列</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="n">all</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">){</span><span class="c1">//转移数量从0到all不等</span>
				<span class="kt">int</span> <span class="n">push_in</span><span class="o">=</span><span class="n">f</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="n">k</span><span class="o">*</span><span class="n">v</span><span class="p">]</span><span class="o">-</span><span class="n">k</span><span class="o">*</span><span class="n">w</span><span class="p">;</span>
				<span class="k">while</span><span class="p">(</span><span class="n">head</span><span class="o">&lt;=</span><span class="n">tail</span><span class="o">&amp;&amp;</span><span class="n">push_in</span><span class="o">&gt;=</span><span class="n">que</span><span class="p">[</span><span class="n">tail</span><span class="p">])</span> <span class="n">tail</span><span class="o">--</span><span class="p">;</span><span class="c1">//维护队列取最大</span>
				<span class="n">tail</span><span class="o">++</span><span class="p">;</span>
				<span class="n">que</span><span class="p">[</span><span class="n">tail</span><span class="p">]</span><span class="o">=</span><span class="n">push_in</span><span class="p">;</span>
				<span class="n">num</span><span class="p">[</span><span class="n">tail</span><span class="p">]</span><span class="o">=</span><span class="n">k</span><span class="p">;</span>
				<span class="k">while</span><span class="p">(</span><span class="n">head</span><span class="o">&lt;=</span><span class="n">tail</span><span class="o">&amp;&amp;</span><span class="n">num</span><span class="p">[</span><span class="n">head</span><span class="p">]</span><span class="o">+</span><span class="n">can_use</span><span class="o">&lt;</span><span class="n">k</span><span class="p">)</span> <span class="n">head</span><span class="o">++</span><span class="p">;</span><span class="c1">//无法实现转移的话</span>
				<span class="n">f</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="n">k</span><span class="o">*</span><span class="n">v</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">f</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="n">k</span><span class="o">*</span><span class="n">v</span><span class="p">],</span><span class="n">que</span><span class="p">[</span><span class="n">head</span><span class="p">]</span><span class="o">+</span><span class="n">k</span><span class="o">*</span><span class="n">w</span><span class="p">);</span>
				<span class="n">tmp</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">tmp</span><span class="p">,</span><span class="n">f</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="n">k</span><span class="o">*</span><span class="n">v</span><span class="p">]);</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">tmp</span><span class="o">+</span><span class="n">ans</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="3-最长公共子序列lcs">3. 最长公共子序列（LCS）</h4>

<p>给定两个序列 X 和 Y ，找出 X 和 Y 的一个最长公共子序列。</p>

<p>状态：\(dp[i][j]=序列X在第i位置序列Y在第j位置的最长公共子序列\)</p>

<p>状态转移方程：
\(dp[i][j]=dp[i-1][j-1]+1,~~X[i]==Y[i];\\
dp[i][j]=max(dp[i-1][j],dp[i][j-1]),~X[i]!=Y[j];\)
时空复杂度都为 \(O(n^2)\)。</p>

<p><a href="https://www.luogu.com.cn/problem/P1439">P1439 最长公共子序列 - 洛谷</a></p>

<p>P1439这题序列长度为1e5，正常复杂度过不了，但是多了排列的限制条件，就可以将此题转化为LIS。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">b</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">len</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="p">;</span>
	<span class="n">map</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span><span class="kt">int</span><span class="o">&gt;</span> <span class="n">mp</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">1</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="p">){</span>
		<span class="kt">int</span> <span class="n">x</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="p">;</span>
		<span class="n">mp</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="n">i</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="mi">1</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="p">){</span>
		<span class="kt">int</span> <span class="n">x</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</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="o">=</span><span class="n">mp</span><span class="p">[</span><span class="n">x</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="mi">1</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="p">){</span>
		<span class="k">if</span><span class="p">(</span><span class="n">b</span><span class="p">[</span><span class="n">len</span><span class="p">]</span><span class="o">&lt;=</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="n">b</span><span class="p">[</span><span class="o">++</span><span class="n">len</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="k">else</span><span class="p">{</span>
			<span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="n">upper_bound</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">b</span><span class="o">+</span><span class="n">len</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="n">i</span><span class="p">])</span><span class="o">-</span><span class="n">b</span><span class="p">;</span>
			<span class="n">b</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">len</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://acm.hdu.edu.cn/showproblem.php?pid=1159">Problem - 1159</a></p>

<p>基础的LCS</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="n">string</span> <span class="n">s1</span><span class="p">,</span><span class="n">s2</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">s1</span><span class="o">&gt;&gt;</span><span class="n">s2</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">n</span><span class="o">=</span><span class="n">s1</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span><span class="n">m</span><span class="o">=</span><span class="n">s2</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
	<span class="n">s1</span><span class="o">=</span><span class="s">" "</span><span class="o">+</span><span class="n">s1</span><span class="p">,</span><span class="n">s2</span><span class="o">=</span><span class="s">" "</span><span class="o">+</span><span class="n">s2</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">1</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="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">1</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="p">){</span>
			<span class="k">if</span><span class="p">(</span><span class="n">s1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">==</span><span class="n">s2</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">dp</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">dp</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</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">else</span> <span class="n">dp</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">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">]);</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="n">m</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="4-最长递增子序列lis">4. 最长递增子序列（LIS）</h4>

<p>给定一个长度为 n 的数组，找出一个最长的单调递增子序列。</p>

<p>状态：\(dp[i]\) 在以第 \(i\) 个数为结尾的最长上升子序列的最大长度</p>

<p>转移方程：\(dp[i]=max(dp[j]+1),0&lt;j&lt;i,A_j&lt;A_i\)</p>

<p>DP不是LIS问题的最优解，使用树状数组或者贪心二分复杂度更低。</p>

<p>使用DP求解是 \(O(n^2)\) 的，采用树状数组或者贪心+二分是 \(Olog_2n\) 的。</p>

<p><a href="https://www.luogu.com.cn/problem/B3637">B3637 最长上升子序列 - 洛谷</a></p>

<pre><code class="language-C++">int dp[N],a[N];//DP
void solve(){
	int n,ans=0;cin&gt;&gt;n;
	for(int i=1;i&lt;=n;i++) cin&gt;&gt;a[i];
	for(int i=1;i&lt;=n;i++){
		dp[i]=1;
		for(int j=1;j&lt;i;j++)
			if(a[i]&gt;a[j]) dp[i]=max(dp[i],dp[j]+1);
		ans=max(ans,dp[i]);
	}
	cout&lt;&lt;ans&lt;&lt;"\n";
}
</code></pre>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">b</span><span class="p">[</span><span class="n">N</span><span class="p">];</span><span class="c1">//贪心+二分</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">len</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</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">i</span><span class="o">=</span><span class="mi">1</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="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
	<span class="n">b</span><span class="p">[</span><span class="o">++</span><span class="n">len</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</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">i</span><span class="o">=</span><span class="mi">2</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="p">){</span>
		<span class="k">if</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="o">&gt;</span><span class="n">b</span><span class="p">[</span><span class="n">len</span><span class="p">])</span> <span class="n">b</span><span class="p">[</span><span class="o">++</span><span class="n">len</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="k">else</span><span class="p">{</span>
			<span class="kt">int</span> <span class="n">x</span><span class="o">=</span><span class="n">lower_bound</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">b</span><span class="o">+</span><span class="n">len</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="n">i</span><span class="p">])</span><span class="o">-</span><span class="n">b</span><span class="p">;</span>
			<span class="n">b</span><span class="p">[</span><span class="n">x</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">len</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://acm.hdu.edu.cn/showproblem.php?pid=1257">Problem - 1257</a></p>

<p>上面这题也是一道LIS的模板。</p>

<h4 id="5-编辑距离">5. 编辑距离</h4>

<p>给定两个单词，计算将第一个单词转换为第二个单词所需的最小操作数。单词允许插入一个字符、删除一个字符、替换一个字符。</p>

<p>状态：\(dp[i][j]\) 表示从 s1 的前 \(i\) 个字符转换到 s2 的前 \(j\) 个字符所需最小操作数。</p>

<p>如果 \(s1[i]==s2[j]\) ，则 \(dp[i][j]=dp[i-1][j-1]\)，因为不需要操作。</p>

<p>如果不等，有三种情况</p>

<ul>
  <li>删除 s1 的最后字符（相当于 s1 最后插入），\(dp[i-1][j]+1\)</li>
  <li>在 s2 插入 s1 的最后字符（相当于 s2 最后删除），\(dp[i][j-1]+1\)</li>
  <li>将某个单词最后字符替换，\(dp[i-1][j-1]+1\)</li>
</ul>

<p>即如果 \(s1[i]!=s2[j]\)，则 \(dp[i][j]=min{dp[i-1][j-1],dp[i-1][j],dp[i][j-1]}+1\)</p>

<p>注意初始化，需要将 \(dp[i][0]和dp[0][i]\) 赋值为 \(i\)，因为某串无字符时，需要删加长度字符。</p>

<p>算法复杂度为 \(O(mn)\)。</p>

<p><a href="https://www.luogu.com.cn/problem/P2758">P2758 编辑距离 - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="n">string</span> <span class="n">s1</span><span class="p">,</span><span class="n">s2</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">s1</span><span class="o">&gt;&gt;</span><span class="n">s2</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">n</span><span class="o">=</span><span class="n">s1</span><span class="p">.</span><span class="n">size</span><span class="p">(),</span><span class="n">m</span><span class="o">=</span><span class="n">s2</span><span class="p">.</span><span class="n">size</span><span class="p">();</span>
	<span class="n">s1</span><span class="o">=</span><span class="s">" "</span><span class="o">+</span><span class="n">s1</span><span class="p">,</span><span class="n">s2</span><span class="o">=</span><span class="s">" "</span><span class="o">+</span><span class="n">s2</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="n">n</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="mi">0</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">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="n">m</span><span class="p">;</span><span class="n">i</span><span class="o">++</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">i</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">i</span><span class="o">=</span><span class="mi">1</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="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">1</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="p">){</span>
			<span class="k">if</span><span class="p">(</span><span class="n">s1</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">==</span><span class="n">s2</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">dp</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">dp</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">];</span>
			<span class="k">else</span> <span class="n">dp</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">min</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span><span class="n">min</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</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="p">}</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="n">m</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="6-最小划分">6. 最小划分</h4>

<p>给出一个正整数数组，把它分成 \(S_1\) 和 \(S_2\) 两部分，使 \(S_1\) 的数字和与 \(S_2\) 的数字和的差绝对值最小。</p>

<p>转化为求最大容量为 \(sum/2\) 的背包问题。</p>

<p><a href="https://www.lintcode.com/problem/724/">724 · 最小划分 - LintCode</a></p>

<p><a href="https://www.luogu.com.cn/problem/P3010">P3010 Dividing the Gold S - 洛谷</a></p>

<p>这题不仅需要求最小差，还需要求方案数量。</p>

<p>可以使状态 \(dp[i]\) 为总和为 \(i\) 的方案数。</p>

<p>初始化为 \(dp[0]=1\)，转移方程为 \(dp[i]+=dp[i-a[i]]\)。</p>

<p>但是需要从后往前求出最接近 \(sum/2\) 的值，但是取模可能会破坏。</p>

<p>所以我们使用一个变量存储。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">ans</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="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">sum</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</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">i</span><span class="o">=</span><span class="mi">1</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="p">){</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</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">i</span><span class="p">];</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="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">i</span><span class="o">=</span><span class="mi">1</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="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">sum</span><span class="o">/</span><span class="mi">2</span><span class="p">;</span><span class="n">j</span><span class="o">&gt;=</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="o">--</span><span class="p">){</span>
			<span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">+=</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">]];</span>
			<span class="k">if</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">ans</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span><span class="n">j</span><span class="p">);</span>
			<span class="n">dp</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="p">}</span>
	<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">sum</span><span class="o">-</span><span class="n">ans</span><span class="o">*</span><span class="mi">2</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="n">ans</span><span class="p">]</span><span class="o">%</span><span class="n">mod</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="7-行走问题">7. 行走问题</h4>

<p>给定一个整数 \(n\) ，表示距离的步骤，一个人每次能走 \(1\sim 3\) 步，问走到 \(n\) 的方案数。</p>

<p>状态：\(dp[i]\) 为走到 \(i\) 的方案数
转移方程：\(dp[i]=dp[i-1]+dp[i-2]+dp[i-3],i&gt;2\)，初始化需判断大小</p>

<p>我觉得可以归结于计数类DP。</p>

<h4 id="8-矩阵最长递增路径">8. 矩阵最长递增路径</h4>

<p>给定一个矩阵，找最长一条路径，要求路径上的数字递增。矩阵的每个点可以向四个方向移动。</p>

<p>第一种方法，记忆化搜索。</p>

<p>第二种方法，DP。</p>

<p>为了满足DP的无后效性，我们需要先从低的点算起，后面高的点对低的没有影响。</p>

<p>从低的点算起可以使用优先队列。</p>

<p>状态：\(dp[i][j]\) 表示以坐标 \((i,j)\) 为终点的最长路径长度</p>

<p>转移方程：\(dp[i][j]=max(dp[i-1][j],dp[i+1][j],dp[i][j-1],dp[i][j+1])+1,a[i][j]&gt;a[next][next]\)</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">nod</span><span class="p">{</span>
	<span class="kt">int</span> <span class="n">i</span><span class="p">,</span><span class="n">j</span><span class="p">,</span><span class="n">num</span><span class="p">;</span>
	<span class="k">friend</span> <span class="kt">bool</span> <span class="k">operator</span> <span class="o">&lt;</span> <span class="p">(</span><span class="n">nod</span> <span class="n">a</span><span class="p">,</span><span class="n">nod</span> <span class="n">b</span><span class="p">){</span>
		<span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">num</span><span class="o">&gt;</span><span class="n">b</span><span class="p">.</span><span class="n">num</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">};</span>
<span class="n">priority_queue</span><span class="o">&lt;</span><span class="n">nod</span><span class="o">&gt;</span> <span class="n">q</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">bu</span><span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span><span class="o">=</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="mi">0</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="mi">0</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="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">m</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">N</span><span class="p">],</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">],</span><span class="n">ans</span><span class="p">;</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</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">1</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="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">1</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="p">){</span>
			<span class="n">dp</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="mi">1</span><span class="p">;</span>
			<span class="n">cin</span><span class="o">&gt;&gt;</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="n">nod</span> <span class="n">x</span><span class="p">;</span><span class="n">x</span><span class="p">.</span><span class="n">i</span><span class="o">=</span><span class="n">i</span><span class="p">,</span><span class="n">x</span><span class="p">.</span><span class="n">j</span><span class="o">=</span><span class="n">j</span><span class="p">,</span><span class="n">x</span><span class="p">.</span><span class="n">num</span><span class="o">=</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="n">q</span><span class="p">.</span><span class="n">push</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="k">while</span><span class="p">(</span><span class="o">!</span><span class="n">q</span><span class="p">.</span><span class="n">empty</span><span class="p">()){</span>
		<span class="n">nod</span> <span class="n">x</span><span class="o">=</span><span class="n">q</span><span class="p">.</span><span class="n">top</span><span class="p">();</span><span class="n">q</span><span class="p">.</span><span class="n">pop</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="p">,</span><span class="n">j</span><span class="o">=</span><span class="n">x</span><span class="p">.</span><span class="n">j</span><span class="p">,</span><span class="n">num</span><span class="o">=</span><span class="n">x</span><span class="p">.</span><span class="n">num</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">4</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">){</span>
			<span class="kt">int</span> <span class="n">xx</span><span class="o">=</span><span class="n">bu</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span><span class="n">yy</span><span class="o">=</span><span class="n">bu</span><span class="p">[</span><span class="n">k</span><span class="p">][</span><span class="mi">1</span><span class="p">];</span>
			<span class="k">if</span><span class="p">(</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">xx</span><span class="p">][</span><span class="n">j</span><span class="o">+</span><span class="n">yy</span><span class="p">]</span><span class="o">&lt;</span><span class="n">num</span><span class="p">)</span> <span class="n">dp</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">max</span><span class="p">(</span><span class="n">dp</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="n">dp</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="n">xx</span><span class="p">][</span><span class="n">j</span><span class="o">+</span><span class="n">yy</span><span class="p">]</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
		<span class="p">}</span>
		<span class="n">ans</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span><span class="n">dp</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="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://www.luogu.com.cn/problem/P1434">P1434  滑雪 - 洛谷</a></p>

<h4 id="9-子集和问题">9. 子集和问题</h4>

<p><strong>题意：</strong>给定一个非负整数的集合 S，一个值 M，问 S 中是否有一个子集，其子集和为 M。</p>

<p><strong>题解：</strong></p>

<p>暴力的时间复杂度为 \(O(2^n)\)。</p>

<p>状态：\(dp[i][j]=1\) 表示 S 的前 i 个元素存在一个子集和等于 j 。</p>

<p>转移方程：</p>

<ul>
  <li>若 \(s[i]&gt;j\)，则不能放入，\(dp[i][j]=dp[i-1][j]\)。</li>
  <li>
    <table>
      <tbody>
        <tr>
          <td>若 \(s[i]&lt;=j\)，可以放或者不放，$$dp[i][j]=dp[i-1][j]~</td>
          <td> </td>
          <td>~dp[i-1][j-s[i]]$$</td>
        </tr>
      </tbody>
    </table>
  </li>
</ul>

<h4 id="10-最优游戏策略">10. 最优游戏策略</h4>

<p><strong>题意：</strong>有 n 堆硬币排成一行，价值为 \(v_i\)，n为偶数；两人交替拿硬币，每次只能拿走第一堆或者最后一堆，先手拿的最大价值是多少？</p>

<p>状态：\(dp[i][j]\) 表示从第 i 堆到第 j 堆区间内，先手能拿到的最大值。</p>

<p>在区间 \([i,j]\) ，先手有两个选择：</p>

<ul>
  <li>拿 i ，接着对手也可以选择拿 i+1 剩下\([i+2,j]\)，或者拿 j 剩下 \([i+1,j-1]\)</li>
  <li>拿 j ，接着对手也可以选择拿 i 剩下 \([i+1,j-1]\)，或者拿 j-1 剩下 \([i,j-2]\)。</li>
</ul>

<p>于是得到状态转移方程：</p>

<ul>
  <li>如果 \(i=j\)，\(dp[i][j]=v[i]\)</li>
  <li>如果 \(i+1=j\)，\(dp[i][j]=max(v[i],v[j])\)</li>
  <li>否则，后手必然对先手不利的拿法，\(dp[i][j]=max(v[i]+min(dp[i+2][j],dp[i+1][j-1]),v[j]+min(dp[i+1][j-1],dp[i][j-2]))\)</li>
</ul>

<p>其实也就变化成了区间DP。</p>

<h4 id="11-矩阵链乘法">11. 矩阵链乘法</h4>

<p><strong>题意：</strong>给出一个数组 p，其中 \(p[i-1]*p[i]\) 表示矩阵 \(A_i\) 的尺寸，输出最少乘法次数。</p>

<p>还是一个区间DP。</p>

<p>状态：\(dp[i][j]\)，表示区间 \([i,j]\) 的最少乘法次数</p>

<p>转移方程：</p>

<ul>
  <li>若 \(i=j\)，\(dp[i][j]=0\)。</li>
  <li>
\[dp[i][j]=min(dp[i][k]+dp[k+1][j]+p_{i-1}p_kp_i),i≤k&lt;j\]
  </li>
</ul>

<h4 id="12-布尔括号问题">12. 布尔括号问题</h4>

<p><strong>题意：</strong>布尔变量有真假两种取值，3 种逻辑操作与、或、异或。现在输入 n 个取值和 n-1 个逻辑操作，要使结果为真，有多少种括号方案？</p>

<p>状态：</p>

<ul>
  <li>\(dp[i][j][1]\) 表示子表达式 \([i,j]\) 结果为true的方式数</li>
  <li>\(dp[i][j][0]\) 表示子表达式 \([i,j]\) 结果为false的方式数</li>
</ul>

<div class="language-c++ 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="kt">bool</span> <span class="nf">evaluate</span><span class="p">(</span><span class="kt">int</span> <span class="n">b1</span><span class="p">,</span> <span class="kt">int</span> <span class="n">b2</span><span class="p">,</span> <span class="kt">char</span> <span class="n">op</span><span class="p">){</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'&amp;'</span><span class="p">)</span> <span class="k">return</span> <span class="n">b1</span> <span class="o">&amp;</span> <span class="n">b2</span><span class="p">;</span>
	<span class="k">if</span> <span class="p">(</span><span class="n">op</span> <span class="o">==</span> <span class="sc">'|'</span><span class="p">)</span> <span class="k">return</span> <span class="n">b1</span> <span class="o">|</span> <span class="n">b2</span><span class="p">;</span>
	<span class="k">return</span> <span class="n">b1</span> <span class="o">^</span> <span class="n">b2</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">countWays</span><span class="p">(</span><span class="n">string</span> <span class="n">s</span><span class="p">){</span>
	<span class="kt">int</span> <span class="n">n</span> <span class="o">=</span> <span class="n">s</span><span class="p">.</span><span class="n">length</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="n">vector</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">&gt;&gt;&gt;</span> <span class="n">dp</span><span class="p">(</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="p">(</span><span class="n">n</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="p">(</span><span class="mi">2</span><span class="p">,</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="mi">0</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="mi">2</span><span class="p">){</span>
		<span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">i</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'T'</span><span class="p">);</span>
		<span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">i</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">s</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'F'</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">len</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">len</span> <span class="o">&lt;</span> <span class="n">n</span><span class="p">;</span> <span class="n">len</span> <span class="o">+=</span> <span class="mi">2</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="n">n</span> <span class="o">-</span> <span class="n">len</span><span class="p">;</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">){</span>
			<span class="kt">int</span> <span class="n">j</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="n">len</span><span class="p">;</span>
			<span class="n">dp</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="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">dp</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="mi">1</span><span class="p">]</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">k</span> <span class="o">=</span> <span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="n">k</span> <span class="o">&lt;</span> <span class="n">j</span><span class="p">;</span> <span class="n">k</span> <span class="o">+=</span> <span class="mi">2</span><span class="p">){</span>
				<span class="kt">char</span> <span class="n">op</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">k</span><span class="p">];</span>
				<span class="kt">int</span> <span class="n">leftTrue</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</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="mi">1</span><span class="p">],</span> <span class="n">leftFalse</span> <span class="o">=</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</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="mi">0</span><span class="p">];</span>
				<span class="kt">int</span> <span class="n">rightTrue</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">j</span><span class="p">][</span><span class="mi">1</span><span class="p">],</span> <span class="n">rightFalse</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">j</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
				<span class="k">if</span> <span class="p">(</span><span class="n">evaluate</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="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftTrue</span> <span class="o">*</span> <span class="n">rightTrue</span><span class="p">;</span>
				<span class="k">if</span> <span class="p">(</span><span class="n">evaluate</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="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftTrue</span> <span class="o">*</span> <span class="n">rightFalse</span><span class="p">;</span>
				<span class="k">if</span> <span class="p">(</span><span class="n">evaluate</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftFalse</span> <span class="o">*</span> <span class="n">rightTrue</span><span class="p">;</span>
				<span class="k">if</span> <span class="p">(</span><span class="n">evaluate</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="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">1</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftFalse</span> <span class="o">*</span> <span class="n">rightFalse</span><span class="p">;</span>
				<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">evaluate</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="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftTrue</span> <span class="o">*</span> <span class="n">rightTrue</span><span class="p">;</span>
				<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">evaluate</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="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftTrue</span> <span class="o">*</span> <span class="n">rightFalse</span><span class="p">;</span>
				<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">evaluate</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftFalse</span> <span class="o">*</span> <span class="n">rightTrue</span><span class="p">;</span>
				<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">evaluate</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="n">op</span><span class="p">))</span>
					<span class="n">dp</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="mi">0</span><span class="p">]</span> <span class="o">+=</span> <span class="n">leftFalse</span> <span class="o">*</span> <span class="n">rightFalse</span><span class="p">;</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="mi">0</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="mi">1</span><span class="p">];</span> 
<span class="p">}</span>

<span class="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="n">string</span> <span class="n">s</span> <span class="o">=</span> <span class="s">"T|T&amp;F^T"</span><span class="p">;</span>
	<span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">countWays</span><span class="p">(</span><span class="n">s</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="13-最短公共超序列">13. 最短公共超序列</h4>

<p><strong>题意：</strong>给定两个字符串，求一个最短的字符串使两个字符串都是它的子序列。</p>

<p>找到两个字符串的LCS，然后将非LCS字符按照原始顺序插入到LCS中。</p>

<p>只求长度的话，\(最短超序列长度=两字符串长度和-LCS长度\)。</p>

<h2 id="3-数位统计dp">3. 数位统计DP</h2>

<h3 id="31-数位dp的递推实现">3.1 数位DP的递推实现</h3>

<h3 id="32-数位dp的记忆化搜索实现">3.2 数位DP的记忆化搜索实现</h3>

<p><a href="https://www.luogu.com.cn/problem/P2602">P2602 数字计数 - 洛谷</a></p>

<p><strong>题意：</strong>在 \([a,b]\) 中，\(0\sim 9\)出现了多少次。</p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mi">15</span><span class="p">;</span>
<span class="n">ll</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</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="c1">//位数,前面几个符合条件,前导0,某位上限</span>
<span class="kt">int</span> <span class="n">num</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">now</span><span class="p">;</span>
<span class="n">ll</span> <span class="nf">dfs</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">sum</span><span class="p">,</span><span class="kt">bool</span> <span class="n">lead</span><span class="p">,</span><span class="kt">bool</span> <span class="n">limit</span><span class="p">){</span>
	<span class="n">ll</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pos</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">sum</span><span class="p">;</span><span class="c1">//递归到0位数，结束返回</span>
	<span class="k">if</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">sum</span><span class="p">][</span><span class="n">lead</span><span class="p">][</span><span class="n">limit</span><span class="p">]</span><span class="o">!=-</span><span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">sum</span><span class="p">][</span><span class="n">lead</span><span class="p">][</span><span class="n">limit</span><span class="p">];</span>
	<span class="kt">int</span> <span class="n">up</span><span class="o">=</span><span class="p">(</span><span class="n">limit</span><span class="o">?</span><span class="n">num</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span><span class="o">:</span><span class="mi">9</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="n">up</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
		<span class="c1">//计算000~099</span>
		<span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="o">==</span><span class="mi">0</span><span class="o">&amp;&amp;</span><span class="n">lead</span><span class="p">)</span> <span class="n">ans</span><span class="o">+=</span><span class="n">dfs</span><span class="p">(</span><span class="n">pos</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">sum</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="n">limit</span><span class="o">&amp;&amp;</span><span class="n">i</span><span class="o">==</span><span class="n">up</span><span class="p">);</span>
		<span class="c1">//计算200~299</span>
		<span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="o">==</span><span class="n">now</span><span class="p">)</span> <span class="n">ans</span><span class="o">+=</span><span class="n">dfs</span><span class="p">(</span><span class="n">pos</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">sum</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="n">limit</span><span class="o">&amp;&amp;</span><span class="n">i</span><span class="o">==</span><span class="n">up</span><span class="p">);</span>
		<span class="c1">//计算100~199</span>
		<span class="k">else</span> <span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="o">!=</span><span class="n">now</span><span class="p">)</span> <span class="n">ans</span><span class="o">+=</span><span class="n">dfs</span><span class="p">(</span><span class="n">pos</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">sum</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">limit</span><span class="o">&amp;&amp;</span><span class="n">i</span><span class="o">==</span><span class="n">up</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">sum</span><span class="p">][</span><span class="n">lead</span><span class="p">][</span><span class="n">limit</span><span class="p">]</span><span class="o">=</span><span class="n">ans</span><span class="p">;</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">ll</span> <span class="n">solve</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">){</span>
	<span class="kt">int</span> <span class="n">len</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="p">){</span>
		<span class="n">num</span><span class="p">[</span><span class="o">++</span><span class="n">len</span><span class="p">]</span><span class="o">=</span><span class="n">x</span><span class="o">%</span><span class="mi">10</span><span class="p">;</span>
		<span class="n">x</span><span class="o">/=</span><span class="mi">10</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="n">memset</span><span class="p">(</span><span class="n">dp</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">dp</span><span class="p">));</span>
	<span class="k">return</span> <span class="n">dfs</span><span class="p">(</span><span class="n">len</span><span class="p">,</span><span class="mi">0</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="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="n">ll</span> <span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="o">&gt;&gt;</span><span class="n">b</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">9</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
		<span class="n">now</span><span class="o">=</span><span class="n">i</span><span class="p">;</span>
		<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">solve</span><span class="p">(</span><span class="n">b</span><span class="p">)</span><span class="o">-</span><span class="n">solve</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="o">&lt;&lt;</span><span class="s">" "</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="33-数位dp例题">3.3 数位DP例题</h3>

<p><a href="https://www.luogu.com.cn/problem/P2657">P2657 windy 数 - 洛谷</a></p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mi">15</span><span class="p">;</span>
<span class="n">ll</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</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="c1">//位数,前面几个符合条件,前导0,某位上限</span>
<span class="kt">int</span> <span class="n">num</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">now</span><span class="p">;</span>
<span class="n">ll</span> <span class="nf">dfs</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">pre</span><span class="p">,</span><span class="kt">bool</span> <span class="n">lead</span><span class="p">,</span><span class="kt">bool</span> <span class="n">limit</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">pos</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">pre</span><span class="p">][</span><span class="n">lead</span><span class="p">][</span><span class="n">limit</span><span class="p">]</span><span class="o">!=-</span><span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">pre</span><span class="p">][</span><span class="n">lead</span><span class="p">][</span><span class="n">limit</span><span class="p">];</span>
	<span class="n">ll</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">up</span><span class="o">=</span><span class="n">limit</span><span class="o">?</span><span class="n">num</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span><span class="o">:</span><span class="mi">9</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="n">up</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
		<span class="k">if</span><span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">i</span><span class="o">-</span><span class="n">pre</span><span class="p">)</span><span class="o">&lt;</span><span class="mi">2</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">i</span><span class="o">==</span><span class="mi">0</span><span class="o">&amp;&amp;</span><span class="n">lead</span><span class="p">)</span> <span class="n">ans</span><span class="o">+=</span><span class="n">dfs</span><span class="p">(</span><span class="n">pos</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="n">limit</span><span class="o">&amp;&amp;</span><span class="n">i</span><span class="o">==</span><span class="n">up</span><span class="p">);</span>
		<span class="k">else</span> <span class="n">ans</span><span class="o">+=</span><span class="n">dfs</span><span class="p">(</span><span class="n">pos</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">i</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">limit</span><span class="o">&amp;&amp;</span><span class="n">i</span><span class="o">==</span><span class="n">up</span><span class="p">);</span>
	<span class="p">}</span>
	<span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">pre</span><span class="p">][</span><span class="n">lead</span><span class="p">][</span><span class="n">limit</span><span class="p">]</span><span class="o">=</span><span class="n">ans</span><span class="p">;</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">ll</span> <span class="n">solve</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">){</span>
	<span class="kt">int</span> <span class="n">len</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="c1">//cout&lt;&lt;"x=="&lt;&lt;x&lt;&lt;"\n";</span>
	<span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="p">){</span>
		<span class="n">num</span><span class="p">[</span><span class="o">++</span><span class="n">len</span><span class="p">]</span><span class="o">=</span><span class="n">x</span><span class="o">%</span><span class="mi">10</span><span class="p">;</span>
		<span class="n">x</span><span class="o">/=</span><span class="mi">10</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="n">memset</span><span class="p">(</span><span class="n">dp</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">dp</span><span class="p">));</span>
	<span class="k">return</span> <span class="n">dfs</span><span class="p">(</span><span class="n">len</span><span class="p">,</span><span class="o">-</span><span class="mi">2</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="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="kt">int</span> <span class="n">T</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="c1">//cin&gt;&gt;T;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">T</span><span class="o">--</span><span class="p">){</span>
		<span class="n">ll</span> <span class="n">a</span><span class="p">,</span><span class="n">x</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="o">&gt;&gt;</span><span class="n">x</span><span class="p">;</span>
<span class="c1">//		cout&lt;&lt;solve(a)&lt;&lt;"\n";</span>
		<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">solve</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="o">-</span><span class="n">solve</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="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://www.luogu.com.cn/problem/P4124">P4124 手机号码 - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ll</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">][</span><span class="n">N</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="mi">2</span><span class="p">];</span><span class="c1">//位数,上上位，上一位，是否有4，是否有8</span>
<span class="kt">int</span> <span class="n">num</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">now</span><span class="p">;</span>
<span class="n">ll</span> <span class="nf">dfs</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">pre1</span><span class="p">,</span><span class="kt">int</span> <span class="n">pre2</span><span class="p">,</span><span class="kt">bool</span> <span class="n">n3</span><span class="p">,</span><span class="kt">bool</span> <span class="n">n4</span><span class="p">,</span><span class="kt">bool</span> <span class="n">n8</span><span class="p">,</span><span class="kt">bool</span> <span class="n">limit</span><span class="p">){</span>
	<span class="k">if</span><span class="p">(</span><span class="n">n4</span><span class="o">&amp;&amp;</span><span class="n">n8</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">pos</span><span class="o">==</span><span class="mi">0</span><span class="p">)</span> <span class="k">return</span> <span class="n">n3</span><span class="p">;</span>
	<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">limit</span><span class="o">&amp;&amp;</span><span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">pre1</span><span class="p">][</span><span class="n">pre2</span><span class="p">][</span><span class="n">n3</span><span class="p">][</span><span class="n">n4</span><span class="p">][</span><span class="n">n8</span><span class="p">]</span><span class="o">!=-</span><span class="mi">1</span><span class="p">)</span> <span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">pre1</span><span class="p">][</span><span class="n">pre2</span><span class="p">][</span><span class="n">n3</span><span class="p">][</span><span class="n">n4</span><span class="p">][</span><span class="n">n8</span><span class="p">];</span>
	<span class="n">ll</span> <span class="n">ans</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="kt">int</span> <span class="n">up</span><span class="o">=</span><span class="n">limit</span><span class="o">?</span><span class="n">num</span><span class="p">[</span><span class="n">pos</span><span class="p">]</span><span class="o">:</span><span class="mi">9</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="n">up</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
		<span class="n">ans</span><span class="o">+=</span><span class="n">dfs</span><span class="p">(</span><span class="n">pos</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">pre2</span><span class="p">,</span><span class="n">i</span><span class="p">,(</span><span class="n">i</span><span class="o">==</span><span class="n">pre1</span><span class="o">&amp;&amp;</span><span class="n">i</span><span class="o">==</span><span class="n">pre2</span><span class="p">)</span><span class="o">||</span><span class="n">n3</span><span class="p">,</span><span class="n">i</span><span class="o">==</span><span class="mi">4</span><span class="o">||</span><span class="n">n4</span><span class="p">,</span><span class="n">i</span><span class="o">==</span><span class="mi">8</span><span class="o">||</span><span class="n">n8</span><span class="p">,</span><span class="n">limit</span><span class="o">&amp;&amp;</span><span class="p">(</span><span class="n">i</span><span class="o">==</span><span class="n">up</span><span class="p">));</span>
	<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">limit</span><span class="p">)</span> <span class="n">dp</span><span class="p">[</span><span class="n">pos</span><span class="p">][</span><span class="n">pre1</span><span class="p">][</span><span class="n">pre2</span><span class="p">][</span><span class="n">n3</span><span class="p">][</span><span class="n">n4</span><span class="p">][</span><span class="n">n8</span><span class="p">]</span><span class="o">=</span><span class="n">ans</span><span class="p">;</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">ll</span> <span class="n">solve</span><span class="p">(</span><span class="n">ll</span> <span class="n">x</span><span class="p">){</span>
	<span class="kt">int</span> <span class="n">len</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">x</span><span class="p">){</span><span class="n">num</span><span class="p">[</span><span class="o">++</span><span class="n">len</span><span class="p">]</span><span class="o">=</span><span class="n">x</span><span class="o">%</span><span class="mi">10</span><span class="p">;</span><span class="n">x</span><span class="o">/=</span><span class="mi">10</span><span class="p">;}</span>
	<span class="k">if</span><span class="p">(</span><span class="n">len</span><span class="o">!=</span><span class="mi">11</span><span class="p">)</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
	<span class="n">memset</span><span class="p">(</span><span class="n">dp</span><span class="p">,</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">dp</span><span class="p">));</span>
	<span class="n">ll</span> <span class="n">ans</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="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">num</span><span class="p">[</span><span class="n">len</span><span class="p">];</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
		<span class="n">ans</span><span class="o">+=</span><span class="n">dfs</span><span class="p">(</span><span class="n">len</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="n">i</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="n">i</span><span class="o">==</span><span class="mi">4</span><span class="p">,</span><span class="n">i</span><span class="o">==</span><span class="mi">8</span><span class="p">,</span><span class="n">i</span><span class="o">==</span><span class="n">num</span><span class="p">[</span><span class="n">len</span><span class="p">]);</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="4-状态压缩dp">4. 状态压缩DP</h2>

<h3 id="41-hamilton问题">4.1 Hamilton问题</h3>

<p>用 \(dp[S][j]\) 表示集合 S 内的最短Hamilton路径。</p>

<p>转移方程：
\(dp[S][j]=min\{dp[S-j][k]+dist(k,j)\},k \in S-j\)</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">dp</span><span class="p">[</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="mi">20</span><span class="p">][</span><span class="mi">21</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dist</span><span class="p">[</span><span class="mi">21</span><span class="p">][</span><span class="mi">21</span><span class="p">];</span>
<span class="kt">int</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="n">memset</span><span class="p">(</span><span class="n">dp</span><span class="p">,</span><span class="mh">0x3f</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">dp</span><span class="p">));</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</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">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="n">n</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="c1">//邻接矩阵</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="n">n</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">)</span>
			<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">dist</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="n">dp</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="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">S</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">S</span><span class="o">&lt;</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="n">n</span><span class="p">);</span><span class="n">S</span><span class="o">++</span><span class="p">)</span><span class="c1">//从小集合扩展到大集合</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="n">n</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">)</span><span class="c1">//枚举点j</span>
			<span class="k">if</span><span class="p">((</span><span class="n">S</span><span class="o">&gt;&gt;</span><span class="n">j</span><span class="p">)</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">)</span><span class="c1">//S中含有点j</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="n">n</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">)</span>
					<span class="k">if</span><span class="p">((</span><span class="n">S</span><span class="o">^</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="n">j</span><span class="p">))</span><span class="o">&gt;&gt;</span><span class="n">k</span><span class="o">&amp;</span><span class="mi">1</span><span class="p">)</span><span class="c1">//k属于S-j集合中</span>
						<span class="n">dp</span><span class="p">[</span><span class="n">S</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">min</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">S</span><span class="p">][</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">S</span><span class="o">^</span><span class="p">(</span><span class="mi">1</span><span class="o">&lt;&lt;</span><span class="n">j</span><span class="p">)][</span><span class="n">k</span><span class="p">]</span><span class="o">+</span><span class="n">dist</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="k">return</span> <span class="n">dp</span><span class="p">[(</span><span class="mi">1</span><span class="o">&lt;&lt;</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">n</span><span class="o">-</span><span class="mi">1</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="42-状压dp原理">4.2 状压DP原理</h3>

<h3 id="43-状压dp例题">4.3 状压DP例题</h3>

<h3 id="44-三进制状压dp">4.4 三进制状压DP</h3>

<p>HDU 3001</p>

<p>状态：\(dp[j][i]\) 表示从城市 j 出发，按路径 i 访问 i 中所有城市的最小费用。</p>

<p>转移方程：
\(dp[j][i]=min(dp[j][i],dp[k][l]+graph[k][j]) ,k \in (i-j)\)
其中，\(l=i-bit[j]\) ，表示从路径 i 中去掉城市 j。</p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">6e4</span><span class="p">,</span><span class="n">inf</span><span class="o">=</span><span class="mh">0x3f3f3f3f</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="kt">int</span> <span class="n">bit</span><span class="p">[</span><span class="mi">12</span><span class="p">]</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">9</span><span class="p">,</span><span class="mi">27</span><span class="p">,</span><span class="mi">81</span><span class="p">,</span><span class="mi">243</span><span class="p">,</span><span class="mi">729</span><span class="p">,</span><span class="mi">2187</span><span class="p">,</span><span class="mi">6561</span><span class="p">,</span><span class="mi">19683</span><span class="p">,</span><span class="mi">59049</span><span class="p">};</span>
<span class="kt">int</span> <span class="n">tri</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="mi">11</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="mi">11</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">graph</span><span class="p">[</span><span class="mi">11</span><span class="p">][</span><span class="mi">11</span><span class="p">];</span><span class="c1">//存图</span>
<span class="kt">void</span> <span class="n">init</span><span class="p">(){</span><span class="c1">//初始化,求所有可能路径</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">59050</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
		<span class="kt">int</span> <span class="n">t</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">1</span><span class="p">;</span><span class="n">j</span><span class="o">&lt;=</span><span class="mi">10</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">){</span>
			<span class="n">tri</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">t</span><span class="o">%</span><span class="mi">3</span><span class="p">;</span>
			<span class="n">t</span><span class="o">/=</span><span class="mi">3</span><span class="p">;</span>
		<span class="p">}</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">com_dp</span><span class="p">(){</span>
	<span class="kt">int</span> <span class="n">ans</span><span class="o">=</span><span class="n">inf</span><span class="p">;</span>
	<span class="n">memset</span><span class="p">(</span><span class="n">dp</span><span class="p">,</span><span class="n">inf</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">dp</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="n">n</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">)</span>
		<span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">bit</span><span class="p">[</span><span class="n">j</span><span class="p">]]</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="c1">//初始化，从第j城市出发，只访问j，费用0</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="n">bit</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">i</span><span class="o">++</span><span class="p">){</span><span class="c1">//遍历所有路径，每个i是一条路径</span>
		<span class="kt">int</span> <span class="n">flag</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="c1">//所有城市都遍历过一次以上</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">1</span><span class="p">;</span><span class="n">j</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">){</span><span class="c1">//遍历城市，以j为起点</span>
			<span class="k">if</span><span class="p">(</span><span class="n">tri</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="mi">0</span><span class="p">){</span><span class="c1">//是否有一个城市访问次数为0</span>
				<span class="n">flag</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="c1">//还没经过所有点</span>
				<span class="k">continue</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">k</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">k</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">){</span><span class="c1">//遍历路径i-j的所有城市</span>
				<span class="kt">int</span> <span class="n">l</span><span class="o">=</span><span class="n">i</span><span class="o">-</span><span class="n">bit</span><span class="p">[</span><span class="n">j</span><span class="p">];</span><span class="c1">//从路径i中去掉第j个城市</span>
				<span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">min</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</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">l</span><span class="p">]</span><span class="o">+</span><span class="n">graph</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="p">}</span>
		<span class="p">}</span>
		<span class="k">if</span><span class="p">(</span><span class="n">flag</span><span class="p">)</span><span class="c1">//找最小费用</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">1</span><span class="p">;</span><span class="n">j</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">)</span>
				<span class="n">ans</span><span class="o">=</span><span class="n">min</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">][</span><span class="n">i</span><span class="p">]);</span><span class="c1">//路径i上最下费用</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="n">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">main</span><span class="p">(){</span>
	<span class="n">init</span><span class="p">();</span>
	<span class="k">while</span><span class="p">(</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">m</span><span class="p">){</span>
		<span class="n">memset</span><span class="p">(</span><span class="n">graph</span><span class="p">,</span><span class="n">inf</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">graph</span><span class="p">));</span>
		<span class="k">while</span><span class="p">(</span><span class="n">m</span><span class="o">--</span><span class="p">){</span>
			<span class="kt">int</span> <span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">,</span><span class="n">c</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="o">&gt;&gt;</span><span class="n">b</span><span class="o">&gt;&gt;</span><span class="n">c</span><span class="p">;</span>
			<span class="k">if</span><span class="p">(</span><span class="n">c</span><span class="o">&lt;</span><span class="n">graph</span><span class="p">[</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">])</span> <span class="n">graph</span><span class="p">[</span><span class="n">a</span><span class="p">][</span><span class="n">b</span><span class="p">]</span><span class="o">=</span><span class="n">graph</span><span class="p">[</span><span class="n">b</span><span class="p">][</span><span class="n">a</span><span class="p">]</span><span class="o">=</span><span class="n">c</span><span class="p">;</span>
		<span class="p">}</span>
		<span class="kt">int</span> <span class="n">ans</span><span class="o">=</span><span class="n">com_dp</span><span class="p">();</span>
		<span class="k">if</span><span class="p">(</span><span class="n">ans</span><span class="o">==</span><span class="n">inf</span><span class="p">)</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"-1</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
		<span class="k">else</span> <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">ans</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="5-区间dp">5. 区间DP</h2>

<h3 id="51-石子合并问题">5.1 石子合并问题</h3>

<p><a href="https://www.luogu.com.cn/problem/P1775">P1775 石子合并（弱化版） - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">b</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="p">;</span>
	<span class="n">memset</span><span class="p">(</span><span class="n">dp</span><span class="p">,</span><span class="mh">0x3f</span><span class="p">,</span><span class="k">sizeof</span><span class="p">(</span><span class="n">dp</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">1</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="p">){</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
		<span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="mi">0</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">len</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">len</span><span class="o">&lt;</span><span class="n">n</span><span class="p">;</span><span class="n">len</span><span class="o">++</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">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">n</span><span class="o">-</span><span class="n">len</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span>
			<span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="n">i</span><span class="o">+</span><span class="n">len</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="n">i</span><span class="p">;</span><span class="n">k</span><span class="o">&lt;</span><span class="n">j</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">){</span>
				<span class="n">dp</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">min</span><span class="p">(</span><span class="n">dp</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="n">dp</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">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">j</span><span class="p">]</span><span class="o">+</span><span class="n">b</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">-</span><span class="n">b</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]);</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">n</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="52-模板代码">5.2 模板代码</h3>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">b</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="c1">//初始化</span>
    
	<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">len</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">len</span><span class="o">&lt;</span><span class="n">n</span><span class="p">;</span><span class="n">len</span><span class="o">++</span><span class="p">)</span><span class="c1">//区间长度</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">1</span><span class="p">;</span><span class="n">i</span><span class="o">&lt;=</span><span class="n">n</span><span class="o">-</span><span class="n">len</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="c1">//区间左端点</span>
			<span class="kt">int</span> <span class="n">j</span><span class="o">=</span><span class="n">i</span><span class="o">+</span><span class="n">len</span><span class="p">;</span><span class="c1">//区间右端点</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="n">i</span><span class="p">;</span><span class="n">k</span><span class="o">&lt;</span><span class="n">j</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">){</span>
				<span class="n">dp</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">min</span><span class="p">(</span><span class="n">dp</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="n">dp</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">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">j</span><span class="p">]</span><span class="o">+</span><span class="n">w</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="p">}</span>
		<span class="p">}</span>
	<span class="k">return</span> <span class="n">dp</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">n</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="53-区间dp例题">5.3 区间DP例题</h3>

<h3 id="54-二维区间dp">5.4 二维区间DP</h3>

<p><a href="https://codeforces.com/contest/1199/problem/F">Problem - F - Codeforces</a></p>

<p><strong>题意：</strong>有一个 n*n 的方格图，某些方块为黑色，其余为白色。一次操作可以选定一个 h*w 的矩形，把其中所有方格涂成白色，代价是 \(max(h,w)\)，求最小代价涂所有方格。</p>

<p>时间复杂度 \(O(n^5)\)。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="n">n</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">];</span>
<span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</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">i</span><span class="o">=</span><span class="mi">1</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="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">1</span><span class="p">;</span><span class="n">j</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</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="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">1</span><span class="p">;</span><span class="n">j</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span><span class="n">j</span><span class="o">++</span><span class="p">)</span>
			<span class="k">if</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="sc">'.'</span><span class="p">)</span> <span class="n">dp</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="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
			<span class="k">else</span> <span class="n">dp</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="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="c1">//黑格涂成白色需一次</span>
	<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">lenx</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">lenx</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span><span class="n">lenx</span><span class="o">++</span><span class="p">)</span>
		<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">leny</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">leny</span><span class="o">&lt;=</span><span class="n">n</span><span class="p">;</span><span class="n">leny</span><span class="o">++</span><span class="p">)</span>
			<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">x1</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">x1</span><span class="o">&lt;=</span><span class="n">n</span><span class="o">-</span><span class="n">lenx</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="n">x1</span><span class="o">++</span><span class="p">)</span>
				<span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">y1</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="n">y1</span><span class="o">&lt;=</span><span class="n">n</span><span class="o">-</span><span class="n">leny</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="p">){</span>
					<span class="kt">int</span> <span class="n">x2</span><span class="o">=</span><span class="n">x1</span><span class="o">+</span><span class="n">lenx</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">y2</span><span class="o">=</span><span class="n">y1</span><span class="o">+</span><span class="n">leny</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">x1</span><span class="o">==</span><span class="n">x2</span><span class="o">&amp;&amp;</span><span class="n">y1</span><span class="o">==</span><span class="n">y2</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
					<span class="n">dp</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="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">abs</span><span class="p">(</span><span class="n">x1</span><span class="o">-</span><span class="n">x2</span><span class="p">),</span><span class="n">abs</span><span class="p">(</span><span class="n">y1</span><span class="o">-</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="c1">//初始值</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="n">x1</span><span class="p">;</span><span class="n">k</span><span class="o">&lt;</span><span class="n">x2</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">)</span>
						<span class="n">dp</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="o">=</span><span class="n">min</span><span class="p">(</span><span class="n">dp</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="n">dp</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">k</span><span class="p">][</span><span class="n">y2</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="o">+</span><span class="mi">1</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">k</span><span class="o">=</span><span class="n">y1</span><span class="p">;</span><span class="n">k</span><span class="o">&lt;</span><span class="n">y2</span><span class="p">;</span><span class="n">k</span><span class="o">++</span><span class="p">)</span>
						<span class="n">dp</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="o">=</span><span class="n">min</span><span class="p">(</span><span class="n">dp</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="n">dp</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">k</span><span class="p">]</span><span class="o">+</span><span class="n">dp</span><span class="p">[</span><span class="n">x1</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">x2</span><span class="p">][</span><span class="n">y2</span><span class="p">]);</span>
				<span class="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</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="n">n</span><span class="p">][</span><span class="n">n</span><span class="p">]</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="6-树形dp">6. 树形DP</h2>

<h3 id="61-树形dp基本操作">6.1 树形DP基本操作</h3>

<p><a href="https://www.luogu.com.cn/problem/P2015">P2015 二叉苹果树 - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">1e2</span><span class="o">+</span><span class="mi">10</span><span class="p">;</span>
<span class="k">struct</span> <span class="nc">nod</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="kt">int</span> <span class="n">w</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span>
<span class="p">};</span>
<span class="n">vector</span><span class="o">&lt;</span><span class="n">nod</span><span class="o">&gt;</span> <span class="n">edge</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="n">N</span><span class="p">],</span><span class="n">sum</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">q</span><span class="p">;</span>
<span class="kt">void</span> <span class="n">dfs</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">,</span><span class="kt">int</span> <span class="n">fa</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="n">edge</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="c1">//用i遍历u的所有子节点</span>
		<span class="kt">int</span> <span class="n">v</span><span class="o">=</span><span class="n">edge</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">v</span><span class="p">,</span><span class="n">w</span><span class="o">=</span><span class="n">edge</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">w</span><span class="p">;</span>
		<span class="k">if</span><span class="p">(</span><span class="n">v</span><span class="o">==</span><span class="n">fa</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span><span class="c1">//不回头搜索，避免循环</span>
		<span class="n">dfs</span><span class="p">(</span><span class="n">v</span><span class="p">,</span><span class="n">u</span><span class="p">);</span><span class="c1">//递归到最深的叶子节点，然后返回</span>
		<span class="n">sum</span><span class="p">[</span><span class="n">u</span><span class="p">]</span><span class="o">+=</span><span class="n">sum</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="c1">//子树上的总边数</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">min</span><span class="p">(</span><span class="n">q</span><span class="p">,</span><span class="n">sum</span><span class="p">[</span><span class="n">u</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="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="n">min</span><span class="p">(</span><span class="n">sum</span><span class="p">[</span><span class="n">v</span><span class="p">],</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">);</span><span class="n">k</span><span class="o">++</span><span class="p">)</span>
				<span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">j</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="n">j</span><span class="o">-</span><span class="n">k</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="n">k</span><span class="p">]</span><span class="o">+</span><span class="n">w</span><span class="p">);</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">q</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">1</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="p">){</span>
		<span class="kt">int</span> <span class="n">u</span><span class="p">,</span><span class="n">v</span><span class="p">,</span><span class="n">w</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">u</span><span class="o">&gt;&gt;</span><span class="n">v</span><span class="o">&gt;&gt;</span><span class="n">w</span><span class="p">;</span>
		<span class="n">edge</span><span class="p">[</span><span class="n">u</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="n">w</span><span class="p">});</span>
		<span class="n">edge</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">push_back</span><span class="p">({</span><span class="n">u</span><span class="p">,</span><span class="n">w</span><span class="p">});</span>
	<span class="p">}</span>
	<span class="n">dfs</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="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">q</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<p><a href="https://www.luogu.com.cn/problem/P1352">P1352 没有上司的舞会 - 洛谷</a></p>

<p>时间复杂度为 \(O(n)\)。</p>

<div class="language-c++ 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">edge</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">dp</span><span class="p">[</span><span class="n">N</span><span class="p">][</span><span class="mi">2</span><span class="p">],</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">fa</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">n</span><span class="p">,</span><span class="n">q</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">dfs</span><span class="p">(</span><span class="kt">int</span> <span class="n">u</span><span class="p">){</span>
	<span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="o">=</span><span class="n">a</span><span class="p">[</span><span class="n">u</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="n">edge</span><span class="p">[</span><span class="n">u</span><span class="p">].</span><span class="n">size</span><span class="p">();</span><span class="n">i</span><span class="o">++</span><span class="p">){</span><span class="c1">//用i遍历u的所有子节点</span>
		<span class="kt">int</span> <span class="n">v</span><span class="o">=</span><span class="n">edge</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">dfs</span><span class="p">(</span><span class="n">v</span><span class="p">);</span>
		<span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span><span class="o">+=</span><span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">];</span>
		<span class="n">dp</span><span class="p">[</span><span class="n">u</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">+=</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">v</span><span class="p">][</span><span class="mi">1</span><span class="p">]);</span>
	<span class="p">}</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</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">i</span><span class="o">=</span><span class="mi">1</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="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</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">i</span><span class="o">=</span><span class="mi">1</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="p">){</span>
		<span class="kt">int</span> <span class="n">u</span><span class="p">,</span><span class="n">v</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">u</span><span class="o">&gt;&gt;</span><span class="n">v</span><span class="p">;</span>
		<span class="n">edge</span><span class="p">[</span><span class="n">v</span><span class="p">].</span><span class="n">push_back</span><span class="p">(</span><span class="n">u</span><span class="p">);</span>
		<span class="n">fa</span><span class="p">[</span><span class="n">u</span><span class="p">]</span><span class="o">=</span><span class="n">v</span><span class="p">;</span>
	<span class="p">}</span>
	<span class="kt">int</span> <span class="n">t</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span>
	<span class="k">while</span><span class="p">(</span><span class="n">fa</span><span class="p">[</span><span class="n">t</span><span class="p">])</span> <span class="n">t</span><span class="o">=</span><span class="n">fa</span><span class="p">[</span><span class="n">t</span><span class="p">];</span>
	<span class="n">dfs</span><span class="p">(</span><span class="n">t</span><span class="p">);</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">max</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">t</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span><span class="n">dp</span><span class="p">[</span><span class="n">t</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="62-背包与树形dp">6.2 背包与树形DP</h3>

<h2 id="7-一般优化">7. 一般优化</h2>

<p><a href="https://www.luogu.com.cn/problem/P3287">P3287 方伯伯的玉米田 - 洛谷</a></p>

<p>树状数组优化</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define lowbit(x) ((x)&amp;-(x))
</span><span class="k">const</span> <span class="kt">int</span> <span class="n">N</span><span class="o">=</span><span class="mf">5e3</span><span class="o">+</span><span class="mi">505</span><span class="p">;</span>
<span class="kt">int</span> <span class="n">a</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">dp</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="mi">505</span><span class="p">],</span><span class="n">t</span><span class="p">[</span><span class="mi">505</span><span class="p">][</span><span class="n">N</span><span class="p">],</span><span class="n">n</span><span class="p">,</span><span class="n">k</span><span class="p">;</span>
<span class="kt">void</span> <span class="nf">update</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">int</span> <span class="n">d</span><span class="p">){</span><span class="c1">//更新区间</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">k</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span><span class="n">i</span><span class="o">+=</span><span class="n">lowbit</span><span class="p">(</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="mi">5500</span><span class="p">;</span><span class="n">j</span><span class="o">+=</span><span class="n">lowbit</span><span class="p">(</span><span class="n">j</span><span class="p">))</span>
			<span class="n">t</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">max</span><span class="p">(</span><span class="n">t</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="n">d</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">int</span> <span class="n">query</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="c1">//查询区间最大值</span>
	<span class="kt">int</span> <span class="n">ans</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">lowbit</span><span class="p">(</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">lowbit</span><span class="p">(</span><span class="n">j</span><span class="p">))</span>
			<span class="n">ans</span><span class="o">=</span><span class="n">max</span><span class="p">(</span><span class="n">ans</span><span class="p">,</span><span class="n">t</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">ans</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">k</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">1</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="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</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">i</span><span class="o">=</span><span class="mi">1</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="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">k</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="p">){</span>
			<span class="n">dp</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">query</span><span class="p">(</span><span class="n">j</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="n">i</span><span class="p">]</span><span class="o">+</span><span class="n">j</span><span class="p">)</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span>
			<span class="n">update</span><span class="p">(</span><span class="n">j</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="n">i</span><span class="p">]</span><span class="o">+</span><span class="n">j</span><span class="p">,</span><span class="n">dp</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="p">}</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">query</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="mi">5500</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="8-单调队列优化">8. 单调队列优化</h2>

<h3 id="81-单调队列优化原理">8.1 单调队列优化原理</h3>

<h3 id="82-单调队列优化例题">8.2 单调队列优化例题</h3>

<p><a href="https://www.luogu.com.cn/problem/P2627">P2627 Mowing the Lawn G - 洛谷</a></p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ll</span> <span class="n">n</span><span class="p">,</span><span class="n">k</span><span class="p">,</span><span class="n">a</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">sum</span><span class="p">[</span><span class="n">N</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">ll</span> <span class="n">ds</span><span class="p">[</span><span class="n">N</span><span class="p">];</span>
<span class="kt">int</span> <span class="n">q</span><span class="p">[</span><span class="n">N</span><span class="p">],</span><span class="n">head</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">tail</span><span class="o">=</span><span class="mi">1</span><span class="p">;</span><span class="c1">//递减的单调队列，队头最大</span>
<span class="n">ll</span> <span class="nf">que_max</span><span class="p">(</span><span class="kt">int</span> <span class="n">j</span><span class="p">){</span>
	<span class="n">ds</span><span class="p">[</span><span class="n">j</span><span class="p">]</span><span class="o">=</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">-</span><span class="n">sum</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
	<span class="k">while</span><span class="p">(</span><span class="n">head</span><span class="o">&lt;=</span><span class="n">tail</span><span class="o">&amp;&amp;</span><span class="n">ds</span><span class="p">[</span><span class="n">q</span><span class="p">[</span><span class="n">tail</span><span class="p">]]</span><span class="o">&lt;</span><span class="n">ds</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> <span class="n">tail</span><span class="o">--</span><span class="p">;</span><span class="c1">//去掉队尾</span>
	<span class="n">q</span><span class="p">[</span><span class="o">++</span><span class="n">tail</span><span class="p">]</span><span class="o">=</span><span class="n">j</span><span class="p">;</span><span class="c1">//进队</span>
	<span class="k">while</span><span class="p">(</span><span class="n">head</span><span class="o">&lt;=</span><span class="n">tail</span><span class="o">&amp;&amp;</span><span class="n">q</span><span class="p">[</span><span class="n">head</span><span class="p">]</span><span class="o">&lt;</span><span class="n">j</span><span class="o">-</span><span class="n">k</span><span class="p">)</span> <span class="n">head</span><span class="o">++</span><span class="p">;</span>
	<span class="k">return</span> <span class="n">ds</span><span class="p">[</span><span class="n">q</span><span class="p">[</span><span class="n">head</span><span class="p">]];</span>
<span class="p">}</span>
<span class="kt">void</span> <span class="n">solve</span><span class="p">(){</span>
	<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="o">&gt;&gt;</span><span class="n">k</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">1</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="p">){</span>
		<span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span><span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="n">a</span><span class="p">[</span><span class="n">i</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="mi">1</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="p">)</span> <span class="n">dp</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">=</span><span class="n">que_max</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="o">+</span><span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
	<span class="n">cout</span><span class="o">&lt;&lt;</span><span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">];</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="9-斜率优化凸壳优化">9. 斜率优化/凸壳优化</h2>

<h3 id="91-状态转移方程变换平面斜率问题">9.1 状态转移方程变换平面斜率问题</h3>

<h3 id="92-求一个dp-i-">9.2 求一个DP[ i ]</h3>

<h3 id="93-求所有dp-i-">9.3 求所有DP[ i ]</h3>

<h3 id="94-例题">9.4 例题</h3>

<h2 id="10-四边形不等式优化">10. 四边形不等式优化</h2>

<h3 id="101-应用场合">10.1 应用场合</h3>

<h3 id="102-四边形不等式优化操作">10.2 四边形不等式优化操作</h3>

<h3 id="103-四边形不等式定义和单调性定义">10.3 四边形不等式定义和单调性定义</h3>

<h3 id="104-四边形不等式定理">10.4 四边形不等式定理</h3>

<h3 id="105-例题">10.5 例题</h3>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="algorithms" /><summary type="html"><![CDATA[《算法竞赛》第5章动态规划全笔记：DP概念、线性DP（分组背包/多重背包/LCS/LIS/编辑距离）、数位DP、状压DP（Hamilton/三进制）、区间DP、树形DP、单调队列优化、斜率优化、四边形不等式优化。]]></summary></entry><entry><title type="html">12届集美大学校赛题解</title><link href="https://tzf0237.github.io/posts/%E9%9B%86%E7%BE%8E%E5%A4%A7%E5%AD%A6%E6%A0%A1%E8%B5%9B%E8%A1%A5%E9%A2%98/" rel="alternate" type="text/html" title="12届集美大学校赛题解" /><published>2025-05-10T00:00:00+08:00</published><updated>2025-05-10T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/%E9%9B%86%E7%BE%8E%E5%A4%A7%E5%AD%A6%E6%A0%A1%E8%B5%9B%E8%A1%A5%E9%A2%98</id><content type="html" xml:base="https://tzf0237.github.io/posts/%E9%9B%86%E7%BE%8E%E5%A4%A7%E5%AD%A6%E6%A0%A1%E8%B5%9B%E8%A1%A5%E9%A2%98/"><![CDATA[<h2 id="12届集美大学校赛题解">12届集美大学校赛题解</h2>

<p>官方难度排序参考：</p>
<ul>
  <li>Easy：GBJHD</li>
  <li>Medium：CAEL</li>
  <li>Hard：KIF</li>
</ul>

<!-- more -->

<h3 id="a-地砖">A. 地砖</h3>

<p><strong>题意</strong>：n×m 的矩形，向每个格子中填充字母，使得所有同字母联通块必须为正方形。最小化从上到下、从左到右的字典序。</p>

<p><strong>题解</strong>：最小化字典序是经典的贪心问题。按照从上到下、从左到右的顺序枚举每一个未填充格子的颜色，判断是否可行。</p>

<h3 id="b-逃离蜂巢">B. 逃离蜂巢</h3>

<p><strong>题意</strong>：有 n 个陷阱，每拆除一个陷阱，生命值先加 a 再减去 b。任意时刻生命值必须为正数，求最优顺序下拆除最多陷阱。</p>

<p><strong>题解</strong>：按 a-b 从大到小排序，按顺序拿取即可。</p>

<h3 id="c-加密通讯">C. 加密通讯</h3>

<p><strong>题意</strong>：给出一个 01 字符串若干子串 1 的个数的奇偶性，构造最小字典序的解。</p>

<p><strong>题解</strong>：考虑该串的前缀异或和 \(s[i]\)，则 \(parity[l,r]=s[r] \wedge s[l-1]\)。经典的 2-SAT 问题。从 0 开始计算，如果遇到没算过的位置 i，让位置 i 的前缀和与位置 i-1 的前缀和值相等。</p>

<h3 id="d-简易量筒">D. 简易量筒</h3>

<p><strong>题意</strong>：有一条河以及 n 个杯子，每个杯子有一个容量。使用这些杯子，能否量出对应体积的水？</p>

<p><strong>题解</strong>：能够量出的体积为 \(\sum_{i=1}^nA_ix_i\)（\(x_i\) 是整数），按照扩展欧几里得定理，一定为 \(gcd(A_1,A_2,...,A_n)\) 的倍数。</p>

<h3 id="e-复杂量筒">E. 复杂量筒</h3>

<p><strong>题意</strong>：有 n 个量筒，第 i 个量筒为 \(i!\)。求量出 \(l \sim r\) 中所有整数体积各一次每个量筒需要用几次。</p>

<p><strong>题解</strong>：最优方案贪心，优先选取 n 号量筒。对于 \(l\sim r\) 中的每个数，写成 \(k*n!+b(b&lt;n!)\) 的形式，k 的部分是等差数列求和，b 的部分预处理前缀和快速得出。</p>

<h3 id="g-电话">G. 电话</h3>

<p><strong>题意</strong>：给出一个电话键盘和一个号码，求手指移动的总长。</p>

<p><strong>题解</strong>：打表预处理按键的位置，直接计算，时间复杂度 \(O(n)\)。</p>

<h3 id="h-花坛">H. 花坛</h3>

<p><strong>题意</strong>：求有多少种合法的方案在 n×m 花坛中放满至多 4 种花，满足不存在同行同种花距离 ≤3，不存在同列同种花距离 ≤3。</p>

<p><strong>题解</strong>：考虑任意同行或同列连续四格必定互异。确定左上 4×4 格后，其余格子全部固定。暴搜左上格子即可。</p>

<h3 id="j-分子测序">J. 分子测序</h3>

<p><strong>题意</strong>：求三维空间中任意三点不共线、任意四点不共面的 n 个顶点的凸多面体有多少个面。</p>

<p><strong>题解</strong>：考虑新添加一个顶点，看作在其中一个面上向外扩展出一个四面体，新增加 4-2=2 个面，答案为 \(2n-4\)。</p>

<h3 id="l-董事会">L. 董事会</h3>

<p><strong>题意</strong>：有 n 个石子组成一个环，每个石子有一个颜色。对于每个 0≤k≤n，判断是否能删除连续的 k 个石子，使得剩下的任意相邻两个石子不同色。</p>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="ACM-ICPC" /><category term="ACM-ICPC" /><category term="algorithms" /><summary type="html"><![CDATA[12届集美大学校赛题解：A地砖、B逃离蜂巢、C加密通讯、D简易量筒、E复杂量筒、G电话、H花坛、J分子测序、L董事会。]]></summary></entry><entry><title type="html">CF Round 1023 (Div. 2) 补题</title><link href="https://tzf0237.github.io/posts/CFdiv21023%E8%A1%A5%E9%A2%98/" rel="alternate" type="text/html" title="CF Round 1023 (Div. 2) 补题" /><published>2025-05-06T00:00:00+08:00</published><updated>2025-05-06T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/CFdiv21023%E8%A1%A5%E9%A2%98</id><content type="html" xml:base="https://tzf0237.github.io/posts/CFdiv21023%E8%A1%A5%E9%A2%98/"><![CDATA[<h2 id="codeforces-round-1023-div-2-补题">Codeforces Round 1023 (Div. 2) 补题</h2>

<p>此次排名情况：</p>

<ul>
  <li>共 8k+，排名 1651，做出 ABC 三题。</li>
  <li>Rating +81，当前为 <code class="language-plaintext highlighter-rouge">1442</code>。</li>
  <li><a href="https://codeforces.com/contest/2107">比赛链接</a></li>
</ul>

<!-- more -->

<h3 id="a-lrc-and-vip">A. LRC and VIP</h3>

<p>题意：有一个长度为 n 的数组 a，你需要将数组分成 2 个序列，每个元素只能属于二者之一，每个序列至少包含一个元素，两个序列全部 GCD 不相等。</p>

<p>题解：当数组 a 中的元素全部相等时，不论序列如何分，两序列 gcd 相等，不可能划分。比较最大值和最小值，如果相等输出 NO。否则将最大值一个元素作为序列，其余的作为另一个序列即可。</p>

<div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">solve</span><span class="p">(){</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</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">a</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">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="n">n</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">a</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="kt">int</span> <span class="n">mn</span><span class="o">=*</span><span class="n">min_element</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="n">a</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
    <span class="kt">int</span> <span class="n">mx</span><span class="o">=*</span><span class="n">max_element</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span><span class="n">a</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
    <span class="k">if</span><span class="p">(</span><span class="n">mn</span><span class="o">==</span><span class="n">mx</span><span class="p">){</span><span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"No</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span><span class="k">return</span><span class="p">;}</span>
    <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="s">"Yes</span><span class="se">\n</span><span class="s">"</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="n">n</span><span class="p">;</span><span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">cout</span><span class="o">&lt;&lt;</span><span class="p">(</span><span class="mi">1</span><span class="o">+</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="o">==</span><span class="n">mx</span><span class="p">))</span><span class="o">&lt;&lt;</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="b-apples-in-boxes">B. Apples in Boxes</h3>

<p>题意：有一个长度为 n 的数组 a，两个人轮流操作。选择一个大于 0 的元素减 1。如果操作后 max(a)-min(a) &gt; k，当前人输。</p>

<p>题解：假设 max-min ≤ k 成立且至少有一个 \(a_i≥1\)。从最大元素中减去不会使条件变差。唯一输的方式是将所有 \(a_i\) 全部减到 0，执行 sum 次操作后全部输掉。</p>

<h3 id="c-maximum-subarray-sum">C. Maximum Subarray Sum</h3>

<p>题意：给你一个长度为 n 的数组 a 和一个正整数 k，数组中有些元素可以任意更改，使最大子数组和正好是 k。</p>

<p>题解：将可替换元素全部改为 -INF，如果最大子数组和仍然大于 k，不可能。选某个可替换元素，计算前面和后面的最大子数组和，然后将这个元素更改为使总和为 k 的值。</p>

<h3 id="d-apple-tree-traversing">D. Apple Tree Traversing</h3>

<p>题意：有一棵 n 个节点的树，每个节点上有一个苹果。选择一条每个节点上都有苹果的路径 (u,v)，写下 (d,u,v) 后去掉路径上所有的苹果。使写下的序列最大。</p>

<p>题解：一棵树中的最长路径为树的直径。假设 \(f_i,g_i\) 是 i 的子树中从 i 出发的最长和第二长路径，则树的直径为 \(max_{i=1}^n f_i+g_i\)。使用 set 和 priority_queue 维护，复杂度 \(O(n log n)\)。</p>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="algorithms" /><summary type="html"><![CDATA[Codeforces Round 1023 (Div. 2) 补题：Rating+81升至1442，做出ABC三题，附D题题解。]]></summary></entry><entry><title type="html">2025年5月4日 贵州省赛M题——递增的鸭鸭</title><link href="https://tzf0237.github.io/posts/%E8%B4%B5%E5%B7%9E%E7%9C%81%E8%B5%9BM%E9%A2%98/" rel="alternate" type="text/html" title="2025年5月4日 贵州省赛M题——递增的鸭鸭" /><published>2025-05-04T00:00:00+08:00</published><updated>2025-05-04T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/%E8%B4%B5%E5%B7%9E%E7%9C%81%E8%B5%9BM%E9%A2%98</id><content type="html" xml:base="https://tzf0237.github.io/posts/%E8%B4%B5%E5%B7%9E%E7%9C%81%E8%B5%9BM%E9%A2%98/"><![CDATA[<h2 id="题目描述">题目描述</h2>

<p>GZU 的农学院在阅湖养了 n 只鸭子，每只鸭子的肉质都有其对应的鲜美度，第 i 只鸭子的鲜美度是在 \([l_i,r_i]\) 中的任意整数。求这 n 只鸭子的鲜美度单调不减的方案数，对 998244353 取模。</p>

<ul>
  <li>输入：第一行一个整数 n (1≤n≤500)；接下来 n 行每行两个整数 \(l_i,r_i (1≤l_i,r_i≤10^9)\)</li>
  <li>输出：满足条件的方案数，对 998244353 取模</li>
</ul>

<!-- more -->

<h2 id="题解">题解</h2>

<h3 id="解法离散化--dp--组合计数">解法：离散化 + DP + 组合计数</h3>

<p>DP 状态：\(dp[j]\) = 前 j 只鸭子的合法方案数。</p>

<p>由于 l 和 r 的取值范围较大（1e9），使用离散化缩小到 1e3。</p>

<p>核心思路：假设这 n 个数的范围相等，都是 [l,r]，那么方案数可以直接用隔板法求出，为 C(n+r-l, n)。</p>

<p>DP 状态转移：遍历所有离散段，在每个段上尝试集中放一段连续的鸭子，使用组合数更新状态。</p>

<p>完整代码：</p>

<div class="language-c++ 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">typedef</span> <span class="kt">long</span> <span class="kt">long</span> <span class="n">ll</span><span class="p">;</span>
<span class="k">const</span> <span class="n">ll</span> <span class="n">MOD</span> <span class="o">=</span> <span class="mi">998244353</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span>
    <span class="kt">int</span> <span class="n">n</span><span class="p">;</span><span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">n</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">l</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">r</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">vt</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">1</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="p">)</span> <span class="n">cin</span><span class="o">&gt;&gt;</span><span class="n">l</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">&gt;&gt;</span><span class="n">r</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="n">vt</span><span class="p">.</span><span class="n">reserve</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span><span class="o">=</span><span class="mi">1</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="p">){</span>
        <span class="n">vt</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">l</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
        <span class="n">vt</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">sort</span><span class="p">(</span><span class="n">vt</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vt</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
    <span class="n">vt</span><span class="p">.</span><span class="n">erase</span><span class="p">(</span><span class="n">unique</span><span class="p">(</span><span class="n">vt</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vt</span><span class="p">.</span><span class="n">end</span><span class="p">()),</span> <span class="n">vt</span><span class="p">.</span><span class="n">end</span><span class="p">());</span>
    <span class="kt">int</span> <span class="n">m</span> <span class="o">=</span> <span class="n">vt</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">len</span><span class="p">(</span><span class="n">m</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="n">m</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">)</span>
        <span class="n">len</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="n">vt</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">vt</span><span class="p">[</span><span class="n">j</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">L</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">R</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="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</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="p">){</span>
        <span class="kt">int</span> <span class="n">Li</span> <span class="o">=</span> <span class="n">lower_bound</span><span class="p">(</span><span class="n">vt</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vt</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">l</span><span class="p">[</span><span class="n">i</span><span class="p">])</span> <span class="o">-</span> <span class="n">vt</span><span class="p">.</span><span class="n">begin</span><span class="p">();</span>
        <span class="kt">int</span> <span class="n">Ri</span> <span class="o">=</span> <span class="n">lower_bound</span><span class="p">(</span><span class="n">vt</span><span class="p">.</span><span class="n">begin</span><span class="p">(),</span> <span class="n">vt</span><span class="p">.</span><span class="n">end</span><span class="p">(),</span> <span class="n">r</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="n">vt</span><span class="p">.</span><span class="n">begin</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">;</span>
        <span class="n">L</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">Li</span><span class="p">;</span> <span class="n">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">Ri</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">inv</span><span class="p">(</span><span class="n">n</span><span class="o">+</span><span class="mi">2</span><span class="p">);</span>
    <span class="n">inv</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="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="o">+</span><span class="mi">1</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
        <span class="n">inv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">MOD</span> <span class="o">-</span> <span class="p">(</span><span class="n">MOD</span><span class="o">/</span><span class="n">i</span><span class="p">)</span> <span class="o">*</span> <span class="n">inv</span><span class="p">[</span><span class="n">MOD</span> <span class="o">%</span> <span class="n">i</span><span class="p">]</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">)</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span>
    <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">dp</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="mi">0</span><span class="p">),</span> <span class="n">dpnext</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="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">s</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">s</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">;</span> <span class="n">s</span><span class="o">++</span><span class="p">){</span>
        <span class="n">vector</span><span class="o">&lt;</span><span class="n">ll</span><span class="o">&gt;</span> <span class="n">f</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="mi">0</span><span class="p">);</span>
        <span class="n">f</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="k">if</span><span class="p">(</span><span class="n">n</span> <span class="o">&gt;=</span> <span class="mi">1</span><span class="p">)</span> <span class="n">f</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">len</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span>
        <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="n">t</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">t</span><span class="o">++</span><span class="p">){</span>
            <span class="n">ll</span> <span class="n">mul</span> <span class="o">=</span> <span class="p">(</span><span class="n">len</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="o">+</span> <span class="n">t</span> <span class="o">-</span> <span class="mi">1</span><span class="p">)</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span>
            <span class="n">f</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="n">f</span><span class="p">[</span><span class="n">t</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">*</span> <span class="n">mul</span> <span class="o">%</span> <span class="n">MOD</span> <span class="o">*</span> <span class="n">inv</span><span class="p">[</span><span class="n">t</span><span class="p">]</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="n">dpnext</span> <span class="o">=</span> <span class="n">dp</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="n">n</span><span class="p">;</span> <span class="n">j</span><span class="o">++</span><span class="p">){</span>
            <span class="k">if</span><span class="p">(</span><span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
            <span class="k">if</span><span class="p">(</span><span class="n">j</span> <span class="o">==</span> <span class="n">n</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
            <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">L</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">s</span> <span class="o">&amp;&amp;</span> <span class="n">s</span> <span class="o">&lt;=</span> <span class="n">R</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">]))</span> <span class="k">continue</span><span class="p">;</span>
            <span class="k">for</span><span class="p">(</span><span class="kt">int</span> <span class="n">t</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">j</span> <span class="o">+</span> <span class="n">t</span> <span class="o">&lt;=</span> <span class="n">n</span><span class="p">;</span> <span class="n">t</span><span class="o">++</span><span class="p">){</span>
                <span class="kt">int</span> <span class="n">duckPos</span> <span class="o">=</span> <span class="n">j</span> <span class="o">+</span> <span class="n">t</span><span class="p">;</span>
                <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="p">(</span><span class="n">L</span><span class="p">[</span><span class="n">duckPos</span><span class="p">]</span> <span class="o">&lt;=</span> <span class="n">s</span> <span class="o">&amp;&amp;</span> <span class="n">s</span> <span class="o">&lt;=</span> <span class="n">R</span><span class="p">[</span><span class="n">duckPos</span><span class="p">]))</span> <span class="k">break</span><span class="p">;</span>
                <span class="n">dpnext</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="n">t</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">dpnext</span><span class="p">[</span><span class="n">j</span><span class="o">+</span><span class="n">t</span><span class="p">]</span> <span class="o">+</span> <span class="n">dp</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">*</span> <span class="n">f</span><span class="p">[</span><span class="n">t</span><span class="p">])</span> <span class="o">%</span> <span class="n">MOD</span><span class="p">;</span>
            <span class="p">}</span>
        <span class="p">}</span>
        <span class="n">dp</span><span class="p">.</span><span class="n">swap</span><span class="p">(</span><span class="n">dpnext</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">dp</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">%</span> <span class="n">MOD</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="ACM-ICPC" /><category term="ACM-ICPC" /><category term="algorithms" /><summary type="html"><![CDATA[贵州省赛M题「递增的鸭鸭」题解：离散化 + 动态规划 + 组合计数（隔板法），DP状态设计及完整代码。]]></summary></entry><entry><title type="html">《算法竞赛入门到进阶》DP学习（1）</title><link href="https://tzf0237.github.io/posts/%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/" rel="alternate" type="text/html" title="《算法竞赛入门到进阶》DP学习（1）" /><published>2025-05-03T00:00:00+08:00</published><updated>2025-05-03T00:00:00+08:00</updated><id>https://tzf0237.github.io/posts/%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95</id><content type="html" xml:base="https://tzf0237.github.io/posts/%E5%AD%A6%E4%B9%A0%E8%AE%B0%E5%BD%95/"><![CDATA[<h2 id="动态规划学习1">动态规划学习（1）</h2>

<p>《算法竞赛入门到进阶》学习。</p>

<!-- more -->

<h2 id="算法竞赛入门到进阶">《算法竞赛入门到进阶》</h2>

<h3 id="1-动态规划的概念和思想">1. 动态规划的概念和思想</h3>

<p>DP（Dynamic Programming）是一种算法思想，不是一个特定的算法。</p>

<p>DP 与分治法的区别：</p>
<ul>
  <li>分治法是将问题分成独立的子问题，每个子问题能独立解决</li>
  <li>DP 的子问题是相关的，前面子问题的解决结果被后面的子问题使用。</li>
</ul>

<p>求解 DP 有 3 步：定义状态、状态转移、算法实现。</p>

<h3 id="2-基础dp">2. 基础DP</h3>

<p>包括硬币问题、0/1 背包、完全背包、最长公共子序列（LCS）、最长递增子序列（LIS）等经典问题。</p>]]></content><author><name>Zifan Tang</name><email>3340589482@qq.com</email></author><category term="algorithms" /><category term="algorithms" /><category term="ACM-ICPC" /><summary type="html"><![CDATA[动态规划学习：DP概念与思想、与分治法的区别、基础DP问题（硬币问题、0/1背包、完全背包、最长公共子序列、最长递增子序列）。]]></summary></entry></feed>