<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>林隙光斑</title><description>Senlyn&apos;s blog</description><link>https://qwq-senlin.cc.cd/</link><language>zh_CN</language><item><title>astro Sätteri 初体验</title><link>https://qwq-senlin.cc.cd/post/astro-Satteri/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/astro-Satteri/</guid><description>markdown 的新解析器</description><pubDate>Sat, 25 Jul 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;认识&lt;/h1&gt;
&lt;p&gt;satteri 是一个新型的 markdown 处理器，另一种则是 unified。听说 satteri 更快。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://satteri.bruits.org/docs&quot;&gt;satteri docs&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;上手&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;import { defineConfig } from &apos;astro/config&apos;;
import { satteri } from &apos;@astrojs/markdown-satteri&apos;;

export default defineConfig({
	markdown: {
		processor: satteri({
			mdastPlugins: [] ,
			hastPlugins: [] ,
			features: {} ,
		}) ,
	},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 mdastPlugins 是 mdast 插件，hastPlugins 是 hast 插件，features 是额外功能。&lt;/p&gt;
&lt;p&gt;比如在 features 中有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gfm&lt;/code&gt;（GitHub Flavored Markdown）：默认 &lt;code&gt;true&lt;/code&gt;，启用表格、脚注、罢线、任务列表以及类似 GitHub 的自动链接。可以定制一些东西，如文档举例的脚注（感觉好奇怪，文档没太看懂）：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;features: {
	gfm: {
		footnotes: {
			label: &quot;脚注文本&quot;,
			backContent: &quot;↑&quot;,
		},
	},
},
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;智能标点符号，如下：&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;smartPunctuation?: boolean | {
  quotes?: boolean
  dashes?: boolean
  ellipses?: boolean
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;quotes 可以转换引号，dashes 破折号（比如多个减号合成破折号），ellipses 省略号（三个英文句号变成省略号）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;math&lt;/code&gt;：默认 &lt;code&gt;false&lt;/code&gt;，开启后还需按照如下方法才能显示（搜索了半天没有找到教程。。最后在 github 抄的代码）：&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;pnpm install @nullpinter/satteri-katex&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在 &lt;code&gt;astro.config.mjs&lt;/code&gt; 导入 &lt;code&gt;import { katex as satteriKatex } from &quot;@nullpinter/satteri-katex&quot;;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;添加 mdast 插件：&lt;code&gt;mdastPlugins: [satteriKatex({ output: &quot;mathml&quot; })]&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;然后重新&lt;code&gt;pnpm dev&lt;/code&gt; 就可以看到效果啦。&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;插件开发&lt;/h1&gt;
&lt;p&gt;这里先贴个&lt;a href=&quot;https://blog.hentioe.dev/posts/satteri-plugin-development.html&quot;&gt;链接&lt;/a&gt;，我现在还用不上，就不学啦。&lt;/p&gt;
</content:encoded></item><item><title>Rust + eframe 学习</title><link>https://qwq-senlin.cc.cd/post/Rust-efame-study/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/Rust-efame-study/</guid><description>其实没学多少哈哈</description><pubDate>Sun, 19 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;从安装开始&lt;/h1&gt;
&lt;p&gt;下载：&lt;a href=&quot;https://www.rust-lang.org/zh-CN/tools/install&quot;&gt;https://www.rust-lang.org/zh-CN/tools/install&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;直接打开，按照默认即可。如果很慢就关掉，输入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; $env:RUSTUP_DIST_SERVER=&quot;https://mirrors.tuna.tsinghua.edu.cn/rustup&quot;
&amp;gt; $env:RUSTUP_UPDATE_ROOT=&quot;https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输入&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; rustc --version
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;出现版本号就成功了。&lt;/p&gt;
&lt;h1&gt;Hello World&lt;/h1&gt;
&lt;p&gt;创建一个程序：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; cargo new HelloWorld
&amp;gt; cd .\HelloWorld\
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以先安装下 GNU 工具链：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; rustup toolchain install stable-gnu
&amp;gt; rustup default stable-gnu
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后输入 &lt;code&gt;cargo run&lt;/code&gt; 运行程序，程序会输出 &lt;code&gt;Hello, world!&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;变量&lt;/h2&gt;
&lt;p&gt;定义（要修改需要加上&lt;code&gt;mut&lt;/code&gt; 标识符）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;let a = 10;&lt;/code&gt; 赋值后不可修改&lt;/li&gt;
&lt;li&gt;&lt;code&gt;const PI: f64 = 3.14159;&lt;/code&gt; 常量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;类型：&lt;code&gt;i32,u64,i128,f64,bool,char&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;元组（固定长度不同类型）：&lt;code&gt;let sb = (&quot;str&quot; , 114 , 5.14);&lt;/code&gt;（取值用&lt;code&gt;sb.0&lt;/code&gt; ）&lt;/p&gt;
&lt;p&gt;数组（固定长度相同类型）：&lt;code&gt;let nums: [i32 ; 3] = [1 , 2 , 3];&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;函数&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;fn f(n: i32) -&amp;gt; i32 { //函数体
	if(n == 0) return 1;
	return f(n - 1) * n;
}
fn add(a: i32 , b: i32) -&amp;gt; i32{ //表达式，返回 a + b
	a + b
}

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;顺序/循环 结构&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;if，没什么特别的，没有括号，其他和 c 一样。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loop&lt;/code&gt; 无限循环，用 &lt;code&gt;break&lt;/code&gt; 退出。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;while i &amp;lt; 3 { i += 1; }&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;for i in 1..4 { println!(&quot;for {}&quot; , i); }&lt;/code&gt; 遍历 1~3&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;进阶&lt;/h1&gt;
&lt;p&gt;速通完 rust，来尝试编写一个桌面应用程序吧！&lt;/p&gt;
&lt;h2&gt;eframe&lt;/h2&gt;
&lt;h3&gt;1. 窗口创建&lt;/h3&gt;
&lt;p&gt;打开 &lt;code&gt;Cargo.toml&lt;/code&gt; 添加依赖：&lt;code&gt;eframe = &quot;0.27&quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后来到 &lt;code&gt;src/main.rs&lt;/code&gt; 在第一行导入库：&lt;code&gt;use eframe::egui;&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fn main() -&amp;gt; Result&amp;lt;(), eframe::Error&amp;gt; {
    let options = eframe::NativeOptions::default();
    eframe::run_native(&quot;My egui App&quot;, options, Box::new(|cc| Box::new(QWQ::new(cc))));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里解释下 &lt;code&gt;run_native&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pub fn run_native(
    title: &amp;amp;str,
    native_options: NativeOptions,
    app_creator: impl FnOnce(&amp;amp;CreationContext) -&amp;gt; Box&amp;lt;dyn App&amp;gt; + &apos;static,
) -&amp;gt; Result&amp;lt;(), Error&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;native_options&lt;/code&gt; 表示窗口配置，比如窗口大小，是否全屏，图标等。代码里是默认值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;app_creator&lt;/code&gt; 是一个闭包函数（相当于匿名函数，&lt;code&gt;| 参数 | 语句块/表达式&lt;/code&gt;），是用来给框架返回应用实例的。&lt;/p&gt;
&lt;p&gt;然后该句没有分号，是表达式，作为 main 的返回值。&lt;/p&gt;
&lt;p&gt;我们接着看剩下的代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#[derive(Default)]
struct QWQ {}

impl QWQ {
    fn new(cc: &amp;amp;eframe::CreationContext&amp;lt;&apos;_&amp;gt;) -&amp;gt; Self {
        Self::default()
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中，&lt;code&gt;QWQ&lt;/code&gt; 是应用状态的结构体。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;#[derive(Default)]&lt;/code&gt; 不是注释，形如 &lt;code&gt;#[..]&lt;/code&gt; 的是 Rust 属性宏，可以给代码附加功能。这行可以自动实现一个 &lt;code&gt;default&lt;/code&gt; 函数，会返回这个结构体的默认值，代码形如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;impl Default for QWQ { // 编译器自动帮你写的代码
    fn default() -&amp;gt; Self { QWQ {} }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们注意到有一个 &lt;code&gt;impl&lt;/code&gt; ，这个是 &lt;code&gt;implementation&lt;/code&gt;（实现）的缩写，开始给类型，结构体等添加方法函数的关键字。&lt;/p&gt;
&lt;p&gt;接下来，实现 eframe 框架的核心，一定要实现 &lt;code&gt;impl eframe::App for XXX&lt;/code&gt; 和函数 &lt;code&gt;update&lt;/code&gt; 。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;impl eframe::App for QWQ {
   fn update(&amp;amp;mut self, ctx: &amp;amp;egui::Context, frame: &amp;amp;mut eframe::Frame) {
       egui::CentralPanel::default().show(ctx, |ui| {
           ui.heading(&quot;Hello World!&quot;);
       });
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里面， self 表示结构体，ctx 用来控制整个 UI，frame 是窗口本身，可以控制窗口关闭。&lt;/p&gt;
&lt;p&gt;然后再在终端中输入 &lt;code&gt;cargo run&lt;/code&gt; 就可以看到界面了。&lt;/p&gt;
&lt;h3&gt;2.&lt;/h3&gt;
&lt;p&gt;可以改 options 来改变窗口配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let mut options = eframe::NativeOptions::default();
options.centered = true;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后我们写出如下代码，比较简单不解释了：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use eframe::egui; 

fn main() -&amp;gt; Result&amp;lt;(), eframe::Error&amp;gt; {
    let mut options = eframe::NativeOptions::default();
    options.centered = true;
    eframe::run_native(&quot;Tools&quot;, options, Box::new(|cc| Box::new(QWQ::new(cc))))

}

#[derive(Default)]
struct QWQ {
    nums: i32 ,
}

impl QWQ {
    fn new(cc: &amp;amp;eframe::CreationContext&amp;lt;&apos;_&amp;gt;) -&amp;gt; Self {
        Self { nums : 0 }
    }
}

impl eframe::App for QWQ {
    fn update(&amp;amp;mut self, ctx: &amp;amp;egui::Context, frame: &amp;amp;mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading(&quot;Hello World!&quot;);
            ui.horizontal(|ui| {
                if ui.button(&quot;dark&quot;).clicked() {
                    ctx.set_visuals(egui::Visuals::dark());
                }
                if ui.button(&quot;light&quot;).clicked() {
                    ctx.set_visuals(egui::Visuals::light());
                }
            });
            ui.label(self.nums.to_string());
       });
       self.nums += 1;
   }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我们运行可以发现，显示的数字只有在鼠标等状态改变时才增加，所以 update 函数就是在这个时候被调用的。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;最终发现，rust 太难了。。。还是 pyhton 好。&lt;/p&gt;
</content:encoded></item><item><title>stm32 学习</title><link>https://qwq-senlin.cc.cd/post/stm32-study/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/stm32-study/</guid><description>stm32 入门记录</description><pubDate>Wed, 15 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;用 cubeIDE。&lt;/p&gt;
&lt;p&gt;延：&lt;code&gt;HAL_Delay()&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;GPIO 输出&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;推挽输出：改变 N-MOS 或 P-MOS，使输出 3.3V 或 0V。&lt;/li&gt;
&lt;li&gt;开漏输出：P-MOS 断，设置为高电平，N-MOS 断，电路短路；设置为低电平，N-MOS 连接，接地，此时外部连电源，则形成电压差，小灯亮起。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;写：&lt;code&gt;HAL_GPIO_WritePin(GPIOX , GPIO_PIN_X , GPIO_PIN_RESET)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;翻转：&lt;code&gt;HAL_GPIO_TogglePin(GPOIX , GPIO_PIN_X)&lt;/code&gt;&lt;/p&gt;
&lt;h1&gt;GPIO 输入&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;上拉输入：按下接地0V，不按3.3V。有上拉电阻。&lt;/li&gt;
&lt;li&gt;下拉输入：按下3.3V，不按接地0V。有下拉电阻。&lt;/li&gt;
&lt;li&gt;浮空输入：无上拉下拉电阻。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;读：&lt;code&gt;HAL_GPIO_ReadPin(同上)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;注意，按键按下有抖动，可以加延时，或者加电容。&lt;/p&gt;
&lt;p&gt;eg：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET){
    HAL_Delay(20);
    while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET);
    HAL_Delay(20);
    if(key_down == GPIO_PIN_RESET) key_down = GPIO_PIN_SET;
    else key_down = GPIO_PIN_RESET;
    HAL_GPIO_WritePin(GPIOA , GPIO_PIN_7 , key_down);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;中断&lt;/h1&gt;
&lt;p&gt;停下主线，做复线，结束后再做主线。&lt;/p&gt;
&lt;p&gt;可以设置优先级。&lt;/p&gt;
&lt;h2&gt;EXTI 外部中断&lt;/h2&gt;
&lt;p&gt;上升沿：低到高电平，中断。&lt;/p&gt;
&lt;p&gt;下降沿：高到低电平，中断。&lt;/p&gt;
&lt;h1&gt;串口&lt;/h1&gt;
&lt;p&gt;PA9：USART1_TX；PA10：USART1_RX。&lt;/p&gt;
&lt;h3&gt;轮询&lt;/h3&gt;
&lt;p&gt;会卡住其他任务。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HAL_UART_Receive(&amp;amp;huart1, qwq, 2, HAL_MAX_DELAY);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HAL_UART_Transmit(&amp;amp;huart1, qwq, 2, 100);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;void HSL_print(int16_t x , char y){
	uint8_t output[32];
	int le = 0;
	output[le++] = y;
	if(x &amp;lt; 0){ output[le++] = &apos;-&apos;; x = -x; }
	else output[le++] = &apos;+&apos;;
	do{
		output[le++] = x % 10 + &apos;0&apos;;
		x /= 10;
	}while(x);
	HAL_UART_Transmit(&amp;amp;huart1, output, le, 100);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;中断&lt;/h3&gt;
&lt;p&gt;不会卡。但是每接受/发生一字节就触发中断&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HAL_UART_Receive_IT(&amp;amp;huart1, qwq, 2);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HAL_UART_Transmit_IT(&amp;amp;huart1, qwq, 2);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中，在 &lt;code&gt;stm32f1xx_it.c&lt;/code&gt; 的这个函数中写有其中断函数：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void USART1_IRQHandler(void){
  HAL_UART_IRQHandler(&amp;amp;huart1);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;来到 &lt;code&gt;stm32f1xx_hal_uart.c&lt;/code&gt; 中可以看到 &lt;code&gt;HAL_UART_IRQHandle&lt;/code&gt; 的实现。其中有回调函数，我们可以重构他们。&lt;/p&gt;
&lt;p&gt;Rx 表示接收，Cplt 表示完成，Callback 回调。&lt;/p&gt;
&lt;p&gt;eg：电脑控制修改闪烁小灯（关键代码）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;uint8_t led_state[2];
uint16_t now_show = GPIO_PIN_6;

void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  HAL_UART_Transmit_IT(&amp;amp;huart1, led_state, 2);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, GPIO_PIN_SET);
  if(led_state[1] == &apos;R&apos;) now_show = GPIO_PIN_6;
  else if(led_state[1] == &apos;B&apos;) now_show = GPIO_PIN_7;
  HAL_UART_Receive_IT(&amp;amp;huart1, led_state, 2);
}

int main(void){
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  HAL_UART_Receive_IT(&amp;amp;huart1, led_state, 2);
  while (1){
	  HAL_GPIO_TogglePin(GPIOA, now_show);
	  HAL_Delay(500);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;DMA&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;HAL_UART_Transmit_DMA(&amp;amp;huart1, led_state, 2);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;HAL_UART_Receive_DMA(&amp;amp;huart1, led_state, 2);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;仍然有中断，在接收/发送完成时触发一次。函数同理。&lt;/p&gt;
&lt;h1&gt;IIC&lt;/h1&gt;
&lt;h2&gt;基础&lt;/h2&gt;
&lt;p&gt;分有 SDA 和 SCL，其中 SCL 是用于同步时钟，SDA 是通信线。在 SCL 输出低电平时，主机设置通信信号，在 SCL 输出高电平时，从机接收信号。结束后接收方发生 ACK 信号表示接收到数据。&lt;/p&gt;
&lt;p&gt;只有在开始或结束时，才会在时钟为高电平时设置数据。即 SCL 同步时钟为高电平时，SDA 由高变低表示起始；反之，SDA 由低变高表示终止。&lt;/p&gt;
&lt;p&gt;地址：四位二进制，高三位是地址，最低位表示读(1)写(0)&lt;/p&gt;
&lt;p&gt;这里用软件 I2C，我把 SCL 接到 PB10，SDA 接到 PB11，所以要设为开漏输出模式。&lt;/p&gt;
&lt;h2&gt;代码&lt;/h2&gt;
&lt;p&gt;MyI2C.c&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;MyI2C.h&quot;

void MyI2C_W_SCL(uint8_t Value){
	HAL_GPIO_WritePin(GPIOB , GPIO_PIN_10 , Value);
}

void MyI2C_W_SDA(uint8_t Value){
	HAL_GPIO_WritePin(GPIOB , GPIO_PIN_11 , Value);
}

uint8_t MyI2C_R_SDA(void){
	return HAL_GPIO_ReadPin(GPIOB , GPIO_PIN_11);
}

void MyI2C_Start(void){
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(0);
}

void MyI2C_Stop(void){
	MyI2C_W_SDA(0);
	MyI2C_W_SCL(1);
	MyI2C_W_SDA(1);
}

void MyI2C_SendByte(uint8_t Byte){
	for(short i = 7;i &amp;gt;= 0;i--){
		MyI2C_W_SDA((Byte &amp;amp; (1 &amp;lt;&amp;lt; i)) &amp;gt;&amp;gt; i);
		MyI2C_W_SCL(1);
		MyI2C_W_SCL(0);
	}
}

uint8_t MyI2C_ReceiveByte(void){
	uint8_t ret = 0;
	MyI2C_W_SDA(1);
	for(short i = 7;i &amp;gt;= 0;i--){
		MyI2C_W_SCL(1);
		ret |= (MyI2C_R_SDA() &amp;lt;&amp;lt; i);
		MyI2C_W_SCL(0);
	}
	return ret;
}

void MyI2C_SendAck(uint8_t Ack){
	MyI2C_W_SDA(Ack);
	MyI2C_W_SCL(1);
	MyI2C_W_SCL(0);
}

uint8_t MyI2C_ReceiveAck(void){
	MyI2C_W_SDA(1);
	MyI2C_W_SCL(1);
	uint8_t ret = MyI2C_R_SDA();
	MyI2C_W_SCL(0);
	return ret;
}

uint8_t MyI2C_SendByte_WithAck(uint8_t Byte){
	MyI2C_SendByte(Byte);
	return MyI2C_ReceiveAck();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MyI2C.h&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#ifndef INC_MYI2C_H_
#define INC_MYI2C_H_

#include &quot;main.h&quot;

void MyI2C_W_SCL(uint8_t Value);
void MyI2C_W_SDA(uint8_t Value);
uint8_t MyI2C_R_SDA(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_SendByte_WithAck(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t Ack);
uint8_t MyI2C_ReceiveAck(void);

#endif
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MPU6050.h&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#ifndef INC_MPU6050_H_
#define INC_MPU6050_H_

#include &quot;MyI2C.h&quot;


// 采样率分频寄存器
#define MPU6050_SMPLRT_DIV   0x19
// 配置寄存器
#define MPU6050_CONFIG       0x1A
// 陀螺仪配置寄存器
#define MPU6050_GYRO_CONFIG  0x1B
// 加速度计配置寄存器
#define MPU6050_ACCEL_CONFIG 0x1C

// 加速度计X轴高位数据寄存器
#define MPU6050_ACCEL_XOUT_H 0x3B
// 加速度计X轴低位数据寄存器
#define MPU6050_ACCEL_XOUT_L 0x3C
// 加速度计Y轴高位数据寄存器
#define MPU6050_ACCEL_YOUT_H 0x3D
// 加速度计Y轴低位数据寄存器
#define MPU6050_ACCEL_YOUT_L 0x3E
// 加速度计Z轴高位数据寄存器
#define MPU6050_ACCEL_ZOUT_H 0x3F
// 加速度计Z轴低位数据寄存器
#define MPU6050_ACCEL_ZOUT_L 0x40
// 温度值高位寄存器
#define MPU6050_TEMP_OUT_H   0x41
// 温度值低位寄存器
#define MPU6050_TEMP_OUT_L   0x42
// 陀螺仪X轴高位数据寄存器
#define MPU6050_GYRO_XOUT_H  0x43
// 陀螺仪X轴低位数据寄存器
#define MPU6050_GYRO_XOUT_L  0x44
// 陀螺仪Y轴高位数据寄存器
#define MPU6050_GYRO_YOUT_H  0x45
// 陀螺仪Y轴低位数据寄存器
#define MPU6050_GYRO_YOUT_L  0x46
// 陀螺仪Z轴高位数据寄存器
#define MPU6050_GYRO_ZOUT_H  0x47
// 陀螺仪Z轴低位数据寄存器
#define MPU6050_GYRO_ZOUT_L  0x48
// 电源管理寄存器1（唤醒芯片核心寄存器）
#define MPU6050_PWR_MGMT_1   0x6B
// 电源管理寄存器2
#define MPU6050_PWR_MGMT_2   0x6C
// 芯片ID寄存器（固定返回0x68）
#define MPU6050_WHO_AM_I     0x75

typedef struct{
	int16_t AccX , AccY , AccZ;
	int16_t GyroX , GyroY , GyroZ;
}ACCELData;

void MPU6050_WriteReg(uint8_t RegAddress , uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_Init(void);
ACCELData MPU6050_GetData(void);

#endif /* INC_MPU6050_H_ */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MPU6050.c&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;MPU6050.h&quot;

#define MPU6050_ADDRESS  0xD0

void MPU6050_WriteReg(uint8_t RegAddress , uint8_t Data){
	MyI2C_Start();
	MyI2C_SendByte_WithAck(MPU6050_ADDRESS);
	MyI2C_SendByte_WithAck(RegAddress);
	MyI2C_SendByte_WithAck(Data);
	MyI2C_Stop();
}

uint8_t MPU6050_ReadReg(uint8_t RegAddress){
	uint8_t ret;
	MyI2C_Start();
	MyI2C_SendByte_WithAck(MPU6050_ADDRESS);
	MyI2C_SendByte_WithAck(RegAddress);

	MyI2C_Start();
	MyI2C_SendByte_WithAck(MPU6050_ADDRESS | 0x01);
	ret = MyI2C_ReceiveByte();
	MyI2C_SendAck(1); //不给应答
	MyI2C_Stop();

	return ret;
}


ACCELData MPU6050_GetData(void){
	ACCELData ret;
	ret.AccX = (((int16_t)(MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H)) &amp;lt;&amp;lt; 8) | (int16_t)(MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L)));
	ret.AccY = (((int16_t)(MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H)) &amp;lt;&amp;lt; 8) | (int16_t)(MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L)));
	ret.AccZ = (((int16_t)(MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H)) &amp;lt;&amp;lt; 8) | (int16_t)(MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L)));
	ret.GyroX = (((int16_t)(MPU6050_ReadReg(MPU6050_GYRO_XOUT_H)) &amp;lt;&amp;lt; 8) | (int16_t)(MPU6050_ReadReg(MPU6050_GYRO_XOUT_L)));
	ret.GyroY = (((int16_t)(MPU6050_ReadReg(MPU6050_GYRO_YOUT_H)) &amp;lt;&amp;lt; 8) | (int16_t)(MPU6050_ReadReg(MPU6050_GYRO_YOUT_L)));
	ret.GyroZ = (((int16_t)(MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H)) &amp;lt;&amp;lt; 8) | (int16_t)(MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L)));
	return ret;
}

void MPU6050_Init(void){\
	HAL_Delay(100);
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x80); // 设备复位
	HAL_Delay(100);  // 等待复位完成
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1 , 0x00); //解除睡眠模式
	HAL_Delay(10);
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2 , 0x00); //不待机
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV , 0x09);
	MPU6050_WriteReg(MPU6050_CONFIG , 0x06);
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG , 0x18); //最大量程
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG , 0x18); //最大量程
	HAL_Delay(50);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;OLED&lt;/h1&gt;
&lt;p&gt;oled.c&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;oled.h&quot;

#define OLED_PAGE 8
#define OLED_ROW 8 * OLED_PAGE
#define OLED_COLUMN 128

uint8_t OLED_GRAM[OLED_PAGE][OLED_COLUMN] , Showed[OLED_PAGE][OLED_COLUMN];

void OLED_Init(void){
	HAL_Delay(100);

	OLED_WriteCommand(0xAE);

	OLED_WriteCommand(0xD5);
	OLED_WriteCommand(0x80);

	OLED_WriteCommand(0xA8);
	OLED_WriteCommand(0x3F);

	OLED_WriteCommand(0xD3);
	OLED_WriteCommand(0x00);

	OLED_WriteCommand(0x81);
	OLED_WriteCommand(0xCF);

	OLED_WriteCommand(0xD9);
	OLED_WriteCommand(0xF1);

	OLED_WriteCommand(0xDB);
	OLED_WriteCommand(0x30);

	OLED_WriteCommand(0xA4);

	OLED_WriteCommand(0xA6);

	OLED_WriteCommand(0x8D);
	OLED_WriteCommand(0x14);

	OLED_WriteCommand(0xAF);

	memset(Showed , 1 , sizeof(Showed));
	OLED_Clear();
	OLED_Update();

	HAL_Delay(100);
}

void OLED_SetCursor(uint8_t X , uint8_t Page){
	OLED_WriteCommand(0x00 | (X &amp;amp; 0x0F)); //0000+X低4位
	OLED_WriteCommand(0x10 | ((X &amp;amp; 0xF0) &amp;gt;&amp;gt; 4)); //0001+X高四位
	OLED_WriteCommand(0xB0 | Page);
}

void OLED_WriteCommand(uint8_t Command){
	MyI2C_Start();
	MyI2C_SendByte_WithAck(0x78);
	MyI2C_SendByte_WithAck(0x00); //D/C位为0，写命令
	MyI2C_SendByte_WithAck(Command);
	MyI2C_Stop();
}

void OLED_WriteData(uint8_t Data){
	MyI2C_Start();
	MyI2C_SendByte_WithAck(0x78);
	MyI2C_SendByte_WithAck(0x40); //D/C位为1，写数据
	MyI2C_SendByte_WithAck(Data);
	MyI2C_Stop();
}

void OLED_Clear(){ memset(OLED_GRAM , 0 , sizeof(OLED_GRAM)); }

#define reverse_uint8_t(x)  do{ \
    (x) = (((x) &amp;amp; 0xAA) &amp;gt;&amp;gt; 1) | (((x) &amp;amp; 0x55) &amp;lt;&amp;lt; 1); \
    (x) = (((x) &amp;amp; 0xCC) &amp;gt;&amp;gt; 2) | (((x) &amp;amp; 0x33) &amp;lt;&amp;lt; 2); \
    (x) = ((x) &amp;gt;&amp;gt; 4) | (((x) &amp;amp; 0x0F) &amp;lt;&amp;lt; 4); \
}while(0)

void OLED_Update(){
	for(uint8_t i = 0 , t , nwpage;i &amp;lt; OLED_PAGE;i++){
		uint8_t lt = OLED_COLUMN;
		nwpage = OLED_PAGE - i - 1;
		for(uint8_t j = 0;j &amp;lt; OLED_COLUMN;j++) if(OLED_GRAM[nwpage][OLED_COLUMN - j - 1] != Showed[i][j]){
			if(j != lt + 1){
				OLED_SetCursor(j , i);
				lt = j;
			}
			t = Showed[i][j] = OLED_GRAM[nwpage][OLED_COLUMN - j - 1];
			reverse_uint8_t(t);
			OLED_WriteData(t);
		}
	}
}

void OLED_SetPixel(uint8_t x , uint8_t y , OLED_Color color){
	if(x &amp;gt;= OLED_COLUMN || y &amp;gt;= OLED_ROW) return ;
	if(!color) OLED_GRAM[y / 8][x] |= (1 &amp;lt;&amp;lt; (y % 8));
	else OLED_GRAM[y / 8][x] &amp;amp;= ~(1 &amp;lt;&amp;lt; (y % 8));
}

void OLED_SetBlock(uint8_t x, uint8_t y, const uint8_t *data, uint8_t w, uint8_t h){
    if(x &amp;gt;= OLED_COLUMN || y &amp;gt;= OLED_ROW) return;
	uint8_t _w = w;
    if(x + w &amp;gt; OLED_COLUMN) w = OLED_COLUMN - x;
    if(y + h &amp;gt; OLED_ROW) h = OLED_ROW - y;

    const uint8_t start_page = y / 8 , start_bit = y % 8;
    for(uint8_t i = 0 , page = (h + 7) / 8; i &amp;lt; w; i++){
		const uint8_t *dot = &amp;amp;data[i];
        for(uint8_t p = 0; p &amp;lt; page; p++){
            uint8_t cur_page = start_page + p;
            if(cur_page &amp;gt;= OLED_PAGE) break;

            if(start_bit){
                OLED_GRAM[cur_page][x + i] |= (*dot) &amp;lt;&amp;lt; (8 - start_bit);
                if(cur_page + 1 &amp;lt; OLED_PAGE)
                    OLED_GRAM[cur_page + 1][x + i] |= (*dot) &amp;gt;&amp;gt; start_bit;
            }
			else OLED_GRAM[cur_page][x + i] = (*dot);
			dot += _w;
        }
    }
}

void OLED_Putchar(uint8_t x , uint8_t y , char ch , const ASCIIFont *font) {
	OLED_SetBlock(x , y , font-&amp;gt;chars + (ch - &apos; &apos;) * (((font-&amp;gt;h + 7) / 8) * font-&amp;gt;w) , font-&amp;gt;w , font-&amp;gt;h);
}

void OLED_Puts_ASCII(uint8_t x , uint8_t y , const char *str , const ASCIIFont *font) {
	uint8_t x0 = x;
	while(*str){
		if(x0 + font -&amp;gt; w &amp;gt; OLED_COLUMN) break;
		OLED_Putchar(x0 , y , *str , font);
		x0 += font -&amp;gt; w;
		str++;
	}
}

char sprintf_tmp[105];
void OLED_Printf_ASCII(uint8_t x , uint8_t y , const ASCIIFont *font , const char *format, ...){
	va_list args;
    va_start(args , format);
	vsnprintf(sprintf_tmp , sizeof(sprintf_tmp) , format , args);
	va_end(args);
	OLED_Puts_ASCII(x , y , sprintf_tmp , font);
}

void OLED_ShowImage(uint8_t x , uint8_t y , const Image *img){
	OLED_SetBlock(x , y , img -&amp;gt; data , img -&amp;gt; w , img -&amp;gt; h);
}

static uint8_t _OLED_GetUTF8Len(char *string) {
	if ((string[0] &amp;amp; 0x80) == 0x00) return 1;
	if ((string[0] &amp;amp; 0xE0) == 0xC0) return 2;
	if ((string[0] &amp;amp; 0xF0) == 0xE0) return 3;
	if ((string[0] &amp;amp; 0xF8) == 0xF0) return 4;
	return 0;
}

void OLED_Puts(uint8_t x , uint8_t y , char *str , const Font *font){
	uint16_t i = 0;
	uint8_t le = (((font -&amp;gt; h + 7) / 8) * font -&amp;gt; w) + 4 , utf8le; // 一个字模占多少字节
	while(str[i]){
		utf8le = _OLED_GetUTF8Len(str + i); if(utf8le == 0) break;
		uint8_t pos = HashGet(font -&amp;gt; hs , CNToInt32(str + i , utf8le));
		if(HashState(font -&amp;gt; hs , pos)){ //未找到
			OLED_Putchar(x , y , (utf8le == 1? str[i] : &apos; &apos;) , font -&amp;gt; ascii);
			x += font -&amp;gt; ascii -&amp;gt; w;
			i += utf8le; //utf8固定占位
			continue;
		}
		OLED_SetBlock(x , y , ((uint8_t *)(font -&amp;gt; chars) + (pos * le)) + 4 , font -&amp;gt; w , font -&amp;gt; h);
		x += font -&amp;gt; w;
		i += utf8le;
	}
}

void OLED_DrawLine(uint8_t x0 , uint8_t y0 , uint8_t x1 , uint8_t y1 , OLED_Color color){
	int16_t dx = x1 - x0 , dy = y1 - y0;
    const int16_t sx = ((dx &amp;gt; 0) &amp;lt;&amp;lt; 1) - 1;
    const int16_t sy = ((dy &amp;gt; 0) &amp;lt;&amp;lt; 1) - 1;
	if(dx &amp;lt; 0) dx = -dx;
	if(dy &amp;gt; 0) dy = -dy;
    int16_t x = x0 , y = y0 , err = dx + dy , err2;
    while(1){
        OLED_SetPixel((uint8_t)x , (uint8_t)y , color);
    	if (x == x1 &amp;amp;&amp;amp; y == y1) break;
		err2 = (err &amp;lt;&amp;lt; 1);
        if (err2 &amp;gt;= dy){
			// if(x == x1) break;
			err += dy; x += sx;
		}
        if (err2 &amp;lt;= dx){
			// if(y == y1) break;
			err += dx; y += sy;
		}
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;oled.h&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#ifndef INC_OLED_H_
#define INC_OLED_H_

#include &quot;MyI2C.h&quot;
#include &quot;string.h&quot;
#include &quot;font.h&quot;
#include &quot;stdio.h&quot;
#include &quot;stdarg.h&quot;

typedef enum {
    OLED_COLOR_WHITE = 0,
    OLED_COLOR_BLACK 
} OLED_Color;

void OLED_Init(void);
void OLED_SetCursor(uint8_t X , uint8_t Page);
void OLED_WriteCommand(uint8_t Command);
void OLED_WriteData(uint8_t Data);
void OLED_Update();
void OLED_Clear();
void OLED_SetPixel(uint8_t x , uint8_t y , OLED_Color color);
void OLED_SetBlock(uint8_t x , uint8_t y , const uint8_t *data , uint8_t w , uint8_t h);
void OLED_Putchar(uint8_t x , uint8_t y , char ch , const ASCIIFont *font);
void OLED_Puts_ASCII(uint8_t x , uint8_t y , const char *str , const ASCIIFont *font);
void OLED_Printf_ASCII(uint8_t x , uint8_t y , const ASCIIFont *font , const char *format , ...);
void OLED_ShowImage(uint8_t x , uint8_t y , const Image *img);
void OLED_Puts(uint8_t x , uint8_t y , char *str , const Font *font);
void OLED_DrawLine(uint8_t x0 , uint8_t y0 , uint8_t x1 , uint8_t y1 , OLED_Color color);


#endif /* INC_OLED_H_ */
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;font.c&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;font.h&quot;

// 8*6 ASCII
const unsigned char ascii_8x6[][6] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // space
    {0x00, 0x00, 0x00, 0x2f, 0x00, 0x00}, // !
    {0x00, 0x00, 0x07, 0x00, 0x07, 0x00}, // &quot;
    {0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14}, // #
    {0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12}, // $
    {0x00, 0x62, 0x64, 0x08, 0x13, 0x23}, // %
    {0x00, 0x36, 0x49, 0x55, 0x22, 0x50}, // &amp;amp;
    {0x00, 0x00, 0x05, 0x03, 0x00, 0x00}, // &apos;
    {0x00, 0x00, 0x1c, 0x22, 0x41, 0x00}, // (
    {0x00, 0x00, 0x41, 0x22, 0x1c, 0x00}, // )
    {0x00, 0x14, 0x08, 0x3E, 0x08, 0x14}, // *
    {0x00, 0x08, 0x08, 0x3E, 0x08, 0x08}, // +
    {0x00, 0x00, 0x00, 0xA0, 0x60, 0x00}, // ,
    {0x00, 0x08, 0x08, 0x08, 0x08, 0x08}, // -
    {0x00, 0x00, 0x60, 0x60, 0x00, 0x00}, // .
    {0x00, 0x20, 0x10, 0x08, 0x04, 0x02}, // /
    {0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E}, // 0
    {0x00, 0x00, 0x42, 0x7F, 0x40, 0x00}, // 1
    {0x00, 0x42, 0x61, 0x51, 0x49, 0x46}, // 2
    {0x00, 0x21, 0x41, 0x45, 0x4B, 0x31}, // 3
    {0x00, 0x18, 0x14, 0x12, 0x7F, 0x10}, // 4
    {0x00, 0x27, 0x45, 0x45, 0x45, 0x39}, // 5
    {0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30}, // 6
    {0x00, 0x01, 0x71, 0x09, 0x05, 0x03}, // 7
    {0x00, 0x36, 0x49, 0x49, 0x49, 0x36}, // 8
    {0x00, 0x06, 0x49, 0x49, 0x29, 0x1E}, // 9
    {0x00, 0x00, 0x36, 0x36, 0x00, 0x00}, // :
    {0x00, 0x00, 0x56, 0x36, 0x00, 0x00}, // ;
    {0x00, 0x08, 0x14, 0x22, 0x41, 0x00}, // &amp;lt;
    {0x00, 0x14, 0x14, 0x14, 0x14, 0x14}, // =
    {0x00, 0x00, 0x41, 0x22, 0x14, 0x08}, // &amp;gt;
    {0x00, 0x02, 0x01, 0x51, 0x09, 0x06}, // ?
    {0x00, 0x32, 0x49, 0x59, 0x51, 0x3E}, // @
    {0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C}, // A
    {0x00, 0x7F, 0x49, 0x49, 0x49, 0x36}, // B
    {0x00, 0x3E, 0x41, 0x41, 0x41, 0x22}, // C
    {0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C}, // D
    {0x00, 0x7F, 0x49, 0x49, 0x49, 0x41}, // E
    {0x00, 0x7F, 0x09, 0x09, 0x09, 0x01}, // F
    {0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A}, // G
    {0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F}, // H
    {0x00, 0x00, 0x41, 0x7F, 0x41, 0x00}, // I
    {0x00, 0x20, 0x40, 0x41, 0x3F, 0x01}, // J
    {0x00, 0x7F, 0x08, 0x14, 0x22, 0x41}, // K
    {0x00, 0x7F, 0x40, 0x40, 0x40, 0x40}, // L
    {0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F}, // M
    {0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F}, // N
    {0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E}, // O
    {0x00, 0x7F, 0x09, 0x09, 0x09, 0x06}, // P
    {0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E}, // Q
    {0x00, 0x7F, 0x09, 0x19, 0x29, 0x46}, // R
    {0x00, 0x46, 0x49, 0x49, 0x49, 0x31}, // S
    {0x00, 0x01, 0x01, 0x7F, 0x01, 0x01}, // T
    {0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F}, // U
    {0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F}, // V
    {0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F}, // W
    {0x00, 0x63, 0x14, 0x08, 0x14, 0x63}, // X
    {0x00, 0x07, 0x08, 0x70, 0x08, 0x07}, // Y
    {0x00, 0x61, 0x51, 0x49, 0x45, 0x43}, // Z
    {0x00, 0x00, 0x7F, 0x41, 0x41, 0x00}, // [
    {0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55}, // 55
    {0x00, 0x00, 0x41, 0x41, 0x7F, 0x00}, // ]
    {0x00, 0x04, 0x02, 0x01, 0x02, 0x04}, // ^
    {0x00, 0x40, 0x40, 0x40, 0x40, 0x40}, // _
    {0x00, 0x00, 0x01, 0x02, 0x04, 0x00}, // &apos;
    {0x00, 0x20, 0x54, 0x54, 0x54, 0x78}, // a
    {0x00, 0x7F, 0x48, 0x44, 0x44, 0x38}, // b
    {0x00, 0x38, 0x44, 0x44, 0x44, 0x20}, // c
    {0x00, 0x38, 0x44, 0x44, 0x48, 0x7F}, // d
    {0x00, 0x38, 0x54, 0x54, 0x54, 0x18}, // e
    {0x00, 0x08, 0x7E, 0x09, 0x01, 0x02}, // f
    {0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C}, // g
    {0x00, 0x7F, 0x08, 0x04, 0x04, 0x78}, // h
    {0x00, 0x00, 0x44, 0x7D, 0x40, 0x00}, // i
    {0x00, 0x40, 0x80, 0x84, 0x7D, 0x00}, // j
    {0x00, 0x7F, 0x10, 0x28, 0x44, 0x00}, // k
    {0x00, 0x00, 0x41, 0x7F, 0x40, 0x00}, // l
    {0x00, 0x7C, 0x04, 0x18, 0x04, 0x78}, // m
    {0x00, 0x7C, 0x08, 0x04, 0x04, 0x78}, // n
    {0x00, 0x38, 0x44, 0x44, 0x44, 0x38}, // o
    {0x00, 0xFC, 0x24, 0x24, 0x24, 0x18}, // p
    {0x00, 0x18, 0x24, 0x24, 0x18, 0xFC}, // q
    {0x00, 0x7C, 0x08, 0x04, 0x04, 0x08}, // r
    {0x00, 0x48, 0x54, 0x54, 0x54, 0x20}, // s
    {0x00, 0x04, 0x3F, 0x44, 0x40, 0x20}, // t
    {0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C}, // u
    {0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C}, // v
    {0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C}, // w
    {0x00, 0x44, 0x28, 0x10, 0x28, 0x44}, // x
    {0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C}, // y
    {0x00, 0x44, 0x64, 0x54, 0x4C, 0x44}, // z
    {0x14, 0x14, 0x14, 0x14, 0x14, 0x14}, // horiz lines
};

const ASCIIFont afont8x6 = {
    .h = 8,
    .w = 6,
    .chars = (unsigned char *)ascii_8x6,
};

const unsigned char ascii_12x6[][12] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot; &quot;,0*/
    {0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}, /*&quot;!&quot;,1*/
    {0x00, 0x0C, 0x02, 0x0C, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;&quot;&quot;,2*/
    {0x90, 0xD0, 0xBC, 0xD0, 0xBC, 0x90, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00}, /*&quot;#&quot;,3*/
    {0x18, 0x24, 0xFE, 0x44, 0x8C, 0x00, 0x03, 0x02, 0x07, 0x02, 0x01, 0x00}, /*&quot;$&quot;,4*/
    {0x18, 0x24, 0xD8, 0xB0, 0x4C, 0x80, 0x00, 0x03, 0x00, 0x01, 0x02, 0x01}, /*&quot;%&quot;,5*/
    {0xC0, 0x38, 0xE4, 0x38, 0xE0, 0x00, 0x01, 0x02, 0x02, 0x01, 0x02, 0x02}, /*&quot;&amp;amp;&quot;,6*/
    {0x08, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;&apos;&quot;,7*/
    {0x00, 0x00, 0x00, 0xF8, 0x04, 0x02, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04}, /*&quot;(&quot;,8*/
    {0x00, 0x02, 0x04, 0xF8, 0x00, 0x00, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00}, /*&quot;)&quot;,9*/
    {0x90, 0x60, 0xF8, 0x60, 0x90, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, /*&quot;*&quot;,10*/
    {0x20, 0x20, 0xFC, 0x20, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00}, /*&quot;+&quot;,11*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x06, 0x00, 0x00, 0x00, 0x00}, /*&quot;,&quot;,12*/
    {0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;-&quot;,13*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00}, /*&quot;.&quot;,14*/
    {0x00, 0x80, 0x60, 0x1C, 0x02, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00}, /*&quot;/&quot;,15*/
    {0xF8, 0x04, 0x04, 0x04, 0xF8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;0&quot;,16*/
    {0x00, 0x08, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00}, /*&quot;1&quot;,17*/
    {0x18, 0x84, 0x44, 0x24, 0x18, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x00}, /*&quot;2&quot;,18*/
    {0x08, 0x04, 0x24, 0x24, 0xD8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;3&quot;,19*/
    {0x40, 0xB0, 0x88, 0xFC, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00}, /*&quot;4&quot;,20*/
    {0x3C, 0x24, 0x24, 0x24, 0xC4, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;5&quot;,21*/
    {0xF8, 0x24, 0x24, 0x2C, 0xC0, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;6&quot;,22*/
    {0x0C, 0x04, 0xE4, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00}, /*&quot;7&quot;,23*/
    {0xD8, 0x24, 0x24, 0x24, 0xD8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;8&quot;,24*/
    {0x38, 0x44, 0x44, 0x44, 0xF8, 0x00, 0x00, 0x03, 0x02, 0x02, 0x01, 0x00}, /*&quot;9&quot;,25*/
    {0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}, /*&quot;:&quot;,26*/
    {0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00}, /*&quot;;&quot;,27*/
    {0x00, 0x20, 0x50, 0x88, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}, /*&quot;&amp;lt;&quot;,28*/
    {0x90, 0x90, 0x90, 0x90, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;=&quot;,29*/
    {0x00, 0x02, 0x04, 0x88, 0x50, 0x20, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00}, /*&quot;&amp;gt;&quot;,30*/
    {0x18, 0x04, 0xC4, 0x24, 0x18, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00}, /*&quot;?&quot;,31*/
    {0xF8, 0x04, 0xE4, 0x94, 0xF8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x02, 0x00}, /*&quot;@&quot;,32*/
    {0x00, 0xE0, 0x9C, 0xF0, 0x80, 0x00, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02}, /*&quot;A&quot;,33*/
    {0x04, 0xFC, 0x24, 0x24, 0xD8, 0x00, 0x02, 0x03, 0x02, 0x02, 0x01, 0x00}, /*&quot;B&quot;,34*/
    {0xF8, 0x04, 0x04, 0x04, 0x0C, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;C&quot;,35*/
    {0x04, 0xFC, 0x04, 0x04, 0xF8, 0x00, 0x02, 0x03, 0x02, 0x02, 0x01, 0x00}, /*&quot;D&quot;,36*/
    {0x04, 0xFC, 0x24, 0x74, 0x0C, 0x00, 0x02, 0x03, 0x02, 0x02, 0x03, 0x00}, /*&quot;E&quot;,37*/
    {0x04, 0xFC, 0x24, 0x74, 0x0C, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00, 0x00}, /*&quot;F&quot;,38*/
    {0xF0, 0x08, 0x04, 0x44, 0xCC, 0x40, 0x00, 0x01, 0x02, 0x02, 0x01, 0x00}, /*&quot;G&quot;,39*/
    {0x04, 0xFC, 0x20, 0x20, 0xFC, 0x04, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02}, /*&quot;H&quot;,40*/
    {0x04, 0x04, 0xFC, 0x04, 0x04, 0x00, 0x02, 0x02, 0x03, 0x02, 0x02, 0x00}, /*&quot;I&quot;,41*/
    {0x00, 0x04, 0x04, 0xFC, 0x04, 0x04, 0x06, 0x04, 0x04, 0x03, 0x00, 0x00}, /*&quot;J&quot;,42*/
    {0x04, 0xFC, 0x24, 0xD0, 0x0C, 0x04, 0x02, 0x03, 0x02, 0x00, 0x03, 0x02}, /*&quot;K&quot;,43*/
    {0x04, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x02, 0x02, 0x03}, /*&quot;L&quot;,44*/
    {0xFC, 0x3C, 0xC0, 0x3C, 0xFC, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00}, /*&quot;M&quot;,45*/
    {0x04, 0xFC, 0x30, 0xC4, 0xFC, 0x04, 0x02, 0x03, 0x02, 0x00, 0x03, 0x00}, /*&quot;N&quot;,46*/
    {0xF8, 0x04, 0x04, 0x04, 0xF8, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;O&quot;,47*/
    {0x04, 0xFC, 0x24, 0x24, 0x18, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00, 0x00}, /*&quot;P&quot;,48*/
    {0xF8, 0x84, 0x84, 0x04, 0xF8, 0x00, 0x01, 0x02, 0x02, 0x07, 0x05, 0x00}, /*&quot;Q&quot;,49*/
    {0x04, 0xFC, 0x24, 0x64, 0x98, 0x00, 0x02, 0x03, 0x02, 0x00, 0x03, 0x02}, /*&quot;R&quot;,50*/
    {0x18, 0x24, 0x24, 0x44, 0x8C, 0x00, 0x03, 0x02, 0x02, 0x02, 0x01, 0x00}, /*&quot;S&quot;,51*/
    {0x0C, 0x04, 0xFC, 0x04, 0x0C, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00}, /*&quot;T&quot;,52*/
    {0x04, 0xFC, 0x00, 0x00, 0xFC, 0x04, 0x00, 0x01, 0x02, 0x02, 0x01, 0x00}, /*&quot;U&quot;,53*/
    {0x04, 0x7C, 0x80, 0xE0, 0x1C, 0x04, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00}, /*&quot;V&quot;,54*/
    {0x1C, 0xE0, 0x3C, 0xE0, 0x1C, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00}, /*&quot;W&quot;,55*/
    {0x04, 0x9C, 0x60, 0x9C, 0x04, 0x00, 0x02, 0x03, 0x00, 0x03, 0x02, 0x00}, /*&quot;X&quot;,56*/
    {0x04, 0x1C, 0xE0, 0x1C, 0x04, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00}, /*&quot;Y&quot;,57*/
    {0x0C, 0x84, 0x64, 0x1C, 0x04, 0x00, 0x02, 0x03, 0x02, 0x02, 0x03, 0x00}, /*&quot;Z&quot;,58*/
    {0x00, 0x00, 0xFE, 0x02, 0x02, 0x00, 0x00, 0x00, 0x07, 0x04, 0x04, 0x00}, /*&quot;[&quot;,59*/
    {0x00, 0x0E, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00}, /*&quot;\&quot;,60*/
    {0x00, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x04, 0x04, 0x07, 0x00, 0x00}, /*&quot;]&quot;,61*/
    {0x00, 0x04, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;^&quot;,62*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, /*&quot;_&quot;,63*/
    {0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;`&quot;,64*/
    {0x00, 0x40, 0xA0, 0xA0, 0xC0, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x02}, /*&quot;a&quot;,65*/
    {0x04, 0xFC, 0x20, 0x20, 0xC0, 0x00, 0x00, 0x03, 0x02, 0x02, 0x01, 0x00}, /*&quot;b&quot;,66*/
    {0x00, 0xC0, 0x20, 0x20, 0x60, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00}, /*&quot;c&quot;,67*/
    {0x00, 0xC0, 0x20, 0x24, 0xFC, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x02}, /*&quot;d&quot;,68*/
    {0x00, 0xC0, 0xA0, 0xA0, 0xC0, 0x00, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00}, /*&quot;e&quot;,69*/
    {0x00, 0x20, 0xF8, 0x24, 0x24, 0x04, 0x00, 0x02, 0x03, 0x02, 0x02, 0x00}, /*&quot;f&quot;,70*/
    {0x00, 0x40, 0xA0, 0xA0, 0x60, 0x20, 0x00, 0x07, 0x0A, 0x0A, 0x0A, 0x04}, /*&quot;g&quot;,71*/
    {0x04, 0xFC, 0x20, 0x20, 0xC0, 0x00, 0x02, 0x03, 0x02, 0x00, 0x03, 0x02}, /*&quot;h&quot;,72*/
    {0x00, 0x20, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00}, /*&quot;i&quot;,73*/
    {0x00, 0x00, 0x20, 0xE4, 0x00, 0x00, 0x08, 0x08, 0x08, 0x07, 0x00, 0x00}, /*&quot;j&quot;,74*/
    {0x04, 0xFC, 0x80, 0xE0, 0x20, 0x20, 0x02, 0x03, 0x02, 0x00, 0x03, 0x02}, /*&quot;k&quot;,75*/
    {0x04, 0x04, 0xFC, 0x00, 0x00, 0x00, 0x02, 0x02, 0x03, 0x02, 0x02, 0x00}, /*&quot;l&quot;,76*/
    {0xE0, 0x20, 0xE0, 0x20, 0xC0, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00}, /*&quot;m&quot;,77*/
    {0x20, 0xE0, 0x20, 0x20, 0xC0, 0x00, 0x02, 0x03, 0x02, 0x00, 0x03, 0x02}, /*&quot;n&quot;,78*/
    {0x00, 0xC0, 0x20, 0x20, 0xC0, 0x00, 0x00, 0x01, 0x02, 0x02, 0x01, 0x00}, /*&quot;o&quot;,79*/
    {0x20, 0xE0, 0x20, 0x20, 0xC0, 0x00, 0x08, 0x0F, 0x0A, 0x02, 0x01, 0x00}, /*&quot;p&quot;,80*/
    {0x00, 0xC0, 0x20, 0x20, 0xE0, 0x00, 0x00, 0x01, 0x02, 0x0A, 0x0F, 0x08}, /*&quot;q&quot;,81*/
    {0x20, 0xE0, 0x40, 0x20, 0x20, 0x00, 0x02, 0x03, 0x02, 0x00, 0x00, 0x00}, /*&quot;r&quot;,82*/
    {0x00, 0x60, 0xA0, 0xA0, 0x20, 0x00, 0x00, 0x02, 0x02, 0x02, 0x03, 0x00}, /*&quot;s&quot;,83*/
    {0x00, 0x20, 0xF8, 0x20, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x02, 0x00}, /*&quot;t&quot;,84*/
    {0x20, 0xE0, 0x00, 0x20, 0xE0, 0x00, 0x00, 0x01, 0x02, 0x02, 0x03, 0x02}, /*&quot;u&quot;,85*/
    {0x20, 0xE0, 0x20, 0x80, 0x60, 0x20, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00}, /*&quot;v&quot;,86*/
    {0x60, 0x80, 0xE0, 0x80, 0x60, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00}, /*&quot;w&quot;,87*/
    {0x20, 0x60, 0x80, 0x60, 0x20, 0x00, 0x02, 0x03, 0x00, 0x03, 0x02, 0x00}, /*&quot;x&quot;,88*/
    {0x20, 0xE0, 0x20, 0x80, 0x60, 0x20, 0x08, 0x08, 0x07, 0x01, 0x00, 0x00}, /*&quot;y&quot;,89*/
    {0x00, 0x20, 0xA0, 0x60, 0x20, 0x00, 0x00, 0x02, 0x03, 0x02, 0x02, 0x00}, /*&quot;z&quot;,90*/
    {0x00, 0x00, 0x20, 0xDE, 0x02, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x00}, /*&quot;{&quot;,91*/
    {0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00}, /*&quot;|&quot;,92*/
    {0x00, 0x02, 0xDE, 0x20, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00}, /*&quot;}&quot;,93*/
    {0x02, 0x01, 0x02, 0x04, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;~&quot;,94*/
};

const ASCIIFont afont12x6 = {
    .h = 12,
    .w = 6,
    .chars = (unsigned char *)ascii_12x6,
};

const unsigned char ascii_16x8[][16] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot; &quot;,0*/
    {0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00}, /*&quot;!&quot;,1*/
    {0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;&quot;&quot;,2*/
    {0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00, 0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00}, /*&quot;#&quot;,3*/
    {0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00, 0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00}, /*&quot;$&quot;,4*/
    {0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00, 0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00}, /*&quot;%&quot;,5*/
    {0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00, 0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10}, /*&quot;&amp;amp;&quot;,6*/
    {0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;&apos;&quot;,7*/
    {0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00}, /*&quot;(&quot;,8*/
    {0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00}, /*&quot;)&quot;,9*/
    {0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00, 0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00}, /*&quot;*&quot;,10*/
    {0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00}, /*&quot;+&quot;,11*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;,&quot;,12*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, /*&quot;-&quot;,13*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;.&quot;,14*/
    {0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04, 0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00}, /*&quot;/&quot;,15*/
    {0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00}, /*&quot;0&quot;,16*/
    {0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00}, /*&quot;1&quot;,17*/
    {0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00}, /*&quot;2&quot;,18*/
    {0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00, 0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00}, /*&quot;3&quot;,19*/
    {0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00}, /*&quot;4&quot;,20*/
    {0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00, 0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00}, /*&quot;5&quot;,21*/
    {0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00}, /*&quot;6&quot;,22*/
    {0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, /*&quot;7&quot;,23*/
    {0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00}, /*&quot;8&quot;,24*/
    {0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00}, /*&quot;9&quot;,25*/
    {0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00}, /*&quot;:&quot;,26*/
    {0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00}, /*&quot;;&quot;,27*/
    {0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00}, /*&quot;&amp;lt;&quot;,28*/
    {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00}, /*&quot;=&quot;,29*/
    {0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00}, /*&quot;&amp;gt;&quot;,30*/
    {0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00}, /*&quot;?&quot;,31*/
    {0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00, 0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00}, /*&quot;@&quot;,32*/
    {0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20}, /*&quot;A&quot;,33*/
    {0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00}, /*&quot;B&quot;,34*/
    {0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00}, /*&quot;C&quot;,35*/
    {0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00}, /*&quot;D&quot;,36*/
    {0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00}, /*&quot;E&quot;,37*/
    {0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00}, /*&quot;F&quot;,38*/
    {0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00}, /*&quot;G&quot;,39*/
    {0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20}, /*&quot;H&quot;,40*/
    {0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00}, /*&quot;I&quot;,41*/
    {0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00}, /*&quot;J&quot;,42*/
    {0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00, 0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00}, /*&quot;K&quot;,43*/
    {0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00}, /*&quot;L&quot;,44*/
    {0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00, 0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00}, /*&quot;M&quot;,45*/
    {0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00}, /*&quot;N&quot;,46*/
    {0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00}, /*&quot;O&quot;,47*/
    {0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00}, /*&quot;P&quot;,48*/
    {0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00}, /*&quot;Q&quot;,49*/
    {0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20}, /*&quot;R&quot;,50*/
    {0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00}, /*&quot;S&quot;,51*/
    {0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00}, /*&quot;T&quot;,52*/
    {0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00}, /*&quot;U&quot;,53*/
    {0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00}, /*&quot;V&quot;,54*/
    {0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00, 0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00}, /*&quot;W&quot;,55*/
    {0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08, 0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20}, /*&quot;X&quot;,56*/
    {0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00}, /*&quot;Y&quot;,57*/
    {0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00}, /*&quot;Z&quot;,58*/
    {0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00}, /*&quot;[&quot;,59*/
    {0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00}, /*&quot;\&quot;,60*/
    {0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00}, /*&quot;]&quot;,61*/
    {0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;^&quot;,62*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}, /*&quot;_&quot;,63*/
    {0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;`&quot;,64*/
    {0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20}, /*&quot;a&quot;,65*/
    {0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00}, /*&quot;b&quot;,66*/
    {0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00}, /*&quot;c&quot;,67*/
    {0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20}, /*&quot;d&quot;,68*/
    {0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00}, /*&quot;e&quot;,69*/
    {0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00}, /*&quot;f&quot;,70*/
    {0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00}, /*&quot;g&quot;,71*/
    {0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20}, /*&quot;h&quot;,72*/
    {0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00}, /*&quot;i&quot;,73*/
    {0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00}, /*&quot;j&quot;,74*/
    {0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00}, /*&quot;k&quot;,75*/
    {0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00}, /*&quot;l&quot;,76*/
    {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F}, /*&quot;m&quot;,77*/
    {0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20}, /*&quot;n&quot;,78*/
    {0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00}, /*&quot;o&quot;,79*/
    {0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00}, /*&quot;p&quot;,80*/
    {0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80}, /*&quot;q&quot;,81*/
    {0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00}, /*&quot;r&quot;,82*/
    {0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00}, /*&quot;s&quot;,83*/
    {0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00}, /*&quot;t&quot;,84*/
    {0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20}, /*&quot;u&quot;,85*/
    {0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00}, /*&quot;v&quot;,86*/
    {0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, 0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00}, /*&quot;w&quot;,87*/
    {0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00}, /*&quot;x&quot;,88*/
    {0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00}, /*&quot;y&quot;,89*/
    {0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00}, /*&quot;z&quot;,90*/
    {0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40}, /*&quot;{&quot;,91*/
    {0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00}, /*&quot;|&quot;,92*/
    {0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00}, /*&quot;}&quot;,93*/
    {0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;~&quot;,94*/
};

const ASCIIFont afont16x8 = {
    .h = 16,
    .w = 8,
    .chars = (unsigned char *)ascii_16x8,
};

const unsigned char ascii_24x12[][36] = {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot; &quot;,0*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00}, /*&quot;!&quot;,1*/
    {0x00, 0x00, 0x80, 0x60, 0x30, 0x1C, 0x8C, 0x60, 0x30, 0x1C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;&quot;&quot;,2*/
    {0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x86, 0xE6, 0x9F, 0x86, 0x86, 0x86, 0x86, 0xE6, 0x9F, 0x86, 0x00, 0x00, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x00}, /*&quot;#&quot;,3*/
    {0x00, 0x00, 0x80, 0xC0, 0x60, 0x20, 0xF8, 0x20, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0C, 0x18, 0xFF, 0x70, 0xE1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x10, 0x10, 0x7F, 0x10, 0x0F, 0x07, 0x00, 0x00}, /*&quot;$&quot;,4*/
    {0x80, 0x60, 0x20, 0x60, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x20, 0x00, 0x00, 0x0F, 0x30, 0x20, 0x30, 0x9F, 0x70, 0xDC, 0x37, 0x10, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x10, 0x0E, 0x03, 0x00, 0x07, 0x18, 0x10, 0x18, 0x07, 0x00}, /*&quot;%&quot;,5*/
    {0x00, 0x00, 0xC0, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0x1F, 0x38, 0xE8, 0x87, 0x03, 0xC4, 0x3C, 0x04, 0x00, 0x00, 0x07, 0x0F, 0x18, 0x10, 0x10, 0x0B, 0x07, 0x0D, 0x10, 0x10, 0x08, 0x00}, /*&quot;&amp;amp;&quot;,6*/
    {0x00, 0x80, 0x8C, 0x4C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;&apos;&quot;,7*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0x30, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x18, 0x20, 0x40, 0x00}, /*&quot;(&quot;,8*/
    {0x00, 0x04, 0x08, 0x30, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;)&quot;,9*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x66, 0x66, 0x3C, 0x18, 0xFF, 0x18, 0x3C, 0x66, 0x66, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;*&quot;,10*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;+&quot;,11*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x8C, 0x4C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;,&quot;,12*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;-&quot;,13*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;.&quot;,14*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x38, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x70, 0x1C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x38, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;/&quot;,15*/
    {0x00, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0x07, 0x0E, 0x18, 0x10, 0x10, 0x18, 0x0E, 0x07, 0x01, 0x00}, /*&quot;0&quot;,16*/
    {0x00, 0x00, 0x80, 0x80, 0x80, 0xC0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x00, 0x00}, /*&quot;1&quot;,17*/
    {0x00, 0x80, 0x40, 0x20, 0x20, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x80, 0x40, 0x20, 0x38, 0x1F, 0x07, 0x00, 0x00, 0x00, 0x1C, 0x1A, 0x19, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1F, 0x00, 0x00}, /*&quot;2&quot;,18*/
    {0x00, 0x80, 0xC0, 0x20, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x10, 0x10, 0x18, 0x2F, 0xE7, 0x80, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x18, 0x0F, 0x07, 0x00, 0x00}, /*&quot;3&quot;,19*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xB0, 0x88, 0x86, 0x81, 0x80, 0xFF, 0xFF, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x00}, /*&quot;4&quot;,20*/
    {0x00, 0x00, 0xE0, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x10, 0x08, 0x08, 0x08, 0x18, 0xF0, 0xE0, 0x00, 0x00, 0x00, 0x07, 0x0B, 0x10, 0x10, 0x10, 0x10, 0x1C, 0x0F, 0x03, 0x00, 0x00}, /*&quot;5&quot;,21*/
    {0x00, 0x00, 0x80, 0xC0, 0x40, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x21, 0x10, 0x08, 0x08, 0x08, 0x18, 0xF0, 0xE0, 0x00, 0x00, 0x01, 0x07, 0x0C, 0x18, 0x10, 0x10, 0x10, 0x08, 0x0F, 0x03, 0x00}, /*&quot;6&quot;,22*/
    {0x00, 0x00, 0xC0, 0xE0, 0x60, 0x60, 0x60, 0x60, 0x60, 0xE0, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xE0, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;7&quot;,23*/
    {0x00, 0x80, 0xC0, 0x60, 0x20, 0x20, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x87, 0xEF, 0x2C, 0x18, 0x18, 0x30, 0x30, 0x68, 0xCF, 0x83, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x10, 0x10, 0x10, 0x10, 0x18, 0x0F, 0x07, 0x00}, /*&quot;8&quot;,24*/
    {0x00, 0x00, 0xC0, 0xC0, 0x20, 0x20, 0x20, 0x20, 0xC0, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x60, 0x40, 0x40, 0x40, 0x20, 0x10, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x0C, 0x1C, 0x10, 0x10, 0x10, 0x08, 0x0F, 0x03, 0x00, 0x00}, /*&quot;9&quot;,25*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00}, /*&quot;:&quot;,26*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;;&quot;,27*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x10, 0x28, 0x44, 0x82, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00}, /*&quot;&amp;lt;&quot;,28*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;=&quot;,29*/
    {0x00, 0x00, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x82, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;&amp;gt;&quot;,30*/
    {0x00, 0xC0, 0x20, 0x20, 0x10, 0x10, 0x10, 0x10, 0x30, 0xE0, 0xC0, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0xF0, 0x10, 0x08, 0x0C, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;?&quot;,31*/
    {0x00, 0x00, 0x00, 0xC0, 0x40, 0x60, 0x20, 0x20, 0x20, 0x40, 0xC0, 0x00, 0x00, 0xFC, 0xFF, 0x01, 0xF0, 0x0E, 0x03, 0xC1, 0xFE, 0x03, 0x80, 0x7F, 0x00, 0x01, 0x07, 0x0E, 0x08, 0x11, 0x11, 0x10, 0x11, 0x09, 0x04, 0x02}, /*&quot;@&quot;,32*/
    {0x00, 0x00, 0x00, 0x00, 0x80, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x43, 0x40, 0x47, 0x7F, 0xF8, 0x80, 0x00, 0x00, 0x10, 0x18, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x1F, 0x1C, 0x10}, /*&quot;A&quot;,33*/
    {0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x18, 0x2F, 0xE7, 0x80, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x0F, 0x07, 0x00}, /*&quot;B&quot;,34*/
    {0x00, 0x00, 0x80, 0xC0, 0x40, 0x20, 0x20, 0x20, 0x20, 0x60, 0xE0, 0x00, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x07, 0x0E, 0x18, 0x10, 0x10, 0x10, 0x08, 0x04, 0x03, 0x00}, /*&quot;C&quot;,35*/
    {0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x40, 0xC0, 0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFE, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x18, 0x08, 0x0E, 0x07, 0x01, 0x00}, /*&quot;D&quot;,36*/
    {0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x06, 0x00}, /*&quot;E&quot;,37*/
    {0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0x60, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x7C, 0x00, 0x00, 0x01, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;F&quot;,38*/
    {0x00, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x20, 0x20, 0x40, 0xE0, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x01, 0x00, 0x00, 0x40, 0x40, 0xC0, 0xC1, 0x40, 0x40, 0x00, 0x01, 0x07, 0x0E, 0x18, 0x10, 0x10, 0x10, 0x0F, 0x0F, 0x00, 0x00}, /*&quot;G&quot;,39*/
    {0x20, 0xE0, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x20, 0xE0, 0xE0, 0x20, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0xFF, 0xFF, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10}, /*&quot;H&quot;,40*/
    {0x00, 0x00, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x00, 0x00}, /*&quot;I&quot;,41*/
    {0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x60, 0xE0, 0x80, 0x80, 0x80, 0xC0, 0x7F, 0x3F, 0x00, 0x00, 0x00}, /*&quot;J&quot;,42*/
    {0x20, 0xE0, 0xE0, 0x20, 0x00, 0x00, 0x20, 0xA0, 0x60, 0x20, 0x20, 0x00, 0x00, 0xFF, 0xFF, 0x30, 0x18, 0x7C, 0xE3, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x01, 0x13, 0x1F, 0x1C, 0x18, 0x10}, /*&quot;K&quot;,43*/
    {0x20, 0xE0, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x06, 0x00}, /*&quot;L&quot;,44*/
    {0x20, 0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0xE0, 0x20, 0x00, 0xFF, 0x01, 0x3F, 0xFE, 0xC0, 0xE0, 0x1E, 0x01, 0xFF, 0xFF, 0x00, 0x10, 0x1F, 0x10, 0x00, 0x03, 0x1F, 0x03, 0x00, 0x10, 0x1F, 0x1F, 0x10}, /*&quot;M&quot;,45*/
    {0x20, 0xE0, 0xE0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xE0, 0x20, 0x00, 0xFF, 0x00, 0x03, 0x07, 0x1C, 0x78, 0xE0, 0x80, 0x00, 0xFF, 0x00, 0x10, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1F, 0x00}, /*&quot;N&quot;,46*/
    {0x00, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0x07, 0x0E, 0x18, 0x10, 0x10, 0x18, 0x0C, 0x07, 0x01, 0x00}, /*&quot;O&quot;,47*/
    {0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x1F, 0x0F, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;P&quot;,48*/
    {0x00, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x01, 0x07, 0x0E, 0x11, 0x11, 0x13, 0x3C, 0x7C, 0x67, 0x21, 0x00}, /*&quot;Q&quot;,49*/
    {0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x60, 0xC0, 0x80, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x10, 0x30, 0xF0, 0xD0, 0x08, 0x0F, 0x07, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x1C, 0x10, 0x10}, /*&quot;R&quot;,50*/
    {0x00, 0x80, 0xC0, 0x60, 0x20, 0x20, 0x20, 0x20, 0x40, 0x40, 0xE0, 0x00, 0x00, 0x07, 0x0F, 0x0C, 0x18, 0x18, 0x30, 0x30, 0x60, 0xE0, 0x81, 0x00, 0x00, 0x1F, 0x0C, 0x08, 0x10, 0x10, 0x10, 0x10, 0x18, 0x0F, 0x07, 0x00}, /*&quot;S&quot;,51*/
    {0x80, 0x60, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x20, 0x20, 0x20, 0x60, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00}, /*&quot;T&quot;,52*/
    {0x20, 0xE0, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xE0, 0x20, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x07, 0x0F, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x08, 0x07, 0x00}, /*&quot;U&quot;,53*/
    {0x20, 0x60, 0xE0, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x20, 0xE0, 0x60, 0x20, 0x00, 0x00, 0x07, 0x7F, 0xF8, 0x80, 0x00, 0x80, 0x7C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1F, 0x1C, 0x07, 0x00, 0x00, 0x00, 0x00}, /*&quot;V&quot;,54*/
    {0x20, 0xE0, 0xE0, 0x20, 0x00, 0xE0, 0xE0, 0x20, 0x00, 0x20, 0xE0, 0x20, 0x00, 0x07, 0xFF, 0xF8, 0xE0, 0x1F, 0xFF, 0xFC, 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1F, 0x03, 0x00, 0x01, 0x1F, 0x03, 0x00, 0x00, 0x00}, /*&quot;W&quot;,55*/
    {0x00, 0x20, 0x60, 0xE0, 0xA0, 0x00, 0x00, 0x20, 0xE0, 0x60, 0x20, 0x00, 0x00, 0x00, 0x00, 0x03, 0x8F, 0x7C, 0xF8, 0xC6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x18, 0x1E, 0x13, 0x00, 0x01, 0x17, 0x1F, 0x18, 0x10, 0x00}, /*&quot;X&quot;,56*/
    {0x20, 0x60, 0xE0, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x20, 0xE0, 0x60, 0x20, 0x00, 0x00, 0x01, 0x07, 0x3E, 0xF8, 0xE0, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x00, 0x00, 0x00}, /*&quot;Y&quot;,57*/
    {0x00, 0x80, 0x60, 0x20, 0x20, 0x20, 0x20, 0xA0, 0xE0, 0xE0, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0x3E, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1C, 0x1F, 0x17, 0x10, 0x10, 0x10, 0x10, 0x18, 0x06, 0x00}, /*&quot;Z&quot;,58*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}, /*&quot;[&quot;,59*/
    {0x00, 0x00, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x1C, 0x60, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0C, 0x70, 0x80, 0x00}, /*&quot;\&quot;,60*/
    {0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00, 0x00}, /*&quot;]&quot;,61*/
    {0x00, 0x00, 0x00, 0x10, 0x08, 0x0C, 0x04, 0x0C, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;^&quot;,62*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}, /*&quot;_&quot;,63*/
    {0x00, 0x00, 0x00, 0x04, 0x04, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;`&quot;,64*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xD8, 0x44, 0x64, 0x24, 0x24, 0xFC, 0xF8, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x18, 0x10, 0x10, 0x10, 0x08, 0x1F, 0x1F, 0x10, 0x18}, /*&quot;a&quot;,65*/
    {0x00, 0x20, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x18, 0x08, 0x04, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x00, 0x00, 0x1F, 0x0F, 0x18, 0x10, 0x10, 0x10, 0x18, 0x0F, 0x03, 0x00}, /*&quot;b&quot;,66*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0x18, 0x04, 0x04, 0x04, 0x3C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x10, 0x10, 0x10, 0x10, 0x08, 0x06, 0x00, 0x00}, /*&quot;c&quot;,67*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0x1C, 0x04, 0x04, 0x04, 0x08, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x18, 0x10, 0x10, 0x10, 0x08, 0x1F, 0x0F, 0x08, 0x00}, /*&quot;d&quot;,68*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0x48, 0x44, 0x44, 0x44, 0x4C, 0x78, 0x70, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x18, 0x10, 0x10, 0x10, 0x08, 0x04, 0x00}, /*&quot;e&quot;,69*/
    {0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x00, 0x04, 0x04, 0x04, 0xFF, 0xFF, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00}, /*&quot;f&quot;,70*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xF8, 0x8C, 0x04, 0x04, 0x8C, 0xF8, 0x74, 0x04, 0x0C, 0x00, 0x70, 0x76, 0xCF, 0x8D, 0x8D, 0x8D, 0x89, 0xC8, 0x78, 0x70, 0x00}, /*&quot;g&quot;,71*/
    {0x00, 0x20, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x08, 0x04, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00}, /*&quot;h&quot;,72*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x00, 0x00}, /*&quot;i&quot;,73*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC0, 0x80, 0x80, 0xC0, 0x7F, 0x3F, 0x00, 0x00, 0x00}, /*&quot;j&quot;,74*/
    {0x00, 0x20, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0xC0, 0xF4, 0x1C, 0x04, 0x04, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x11, 0x00, 0x03, 0x1F, 0x1C, 0x10, 0x10, 0x00}, /*&quot;k&quot;,75*/
    {0x00, 0x00, 0x20, 0x20, 0x20, 0xE0, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x00, 0x00}, /*&quot;l&quot;,76*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x08, 0x04, 0xFC, 0xFC, 0x08, 0x04, 0xFC, 0xFC, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x1F, 0x1F, 0x10, 0x00, 0x1F, 0x1F, 0x10}, /*&quot;m&quot;,77*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x08, 0x08, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00, 0x00, 0x10, 0x1F, 0x1F, 0x10, 0x00}, /*&quot;n&quot;,78*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF0, 0x18, 0x0C, 0x04, 0x04, 0x0C, 0x18, 0xF0, 0xE0, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x10, 0x10, 0x10, 0x10, 0x0C, 0x0F, 0x03, 0x00}, /*&quot;o&quot;,79*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x08, 0x04, 0x04, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x88, 0x90, 0x10, 0x10, 0x1C, 0x0F, 0x03, 0x00}, /*&quot;p&quot;,80*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0x1C, 0x04, 0x04, 0x04, 0x08, 0xF8, 0xFC, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x18, 0x10, 0x10, 0x90, 0x88, 0xFF, 0xFF, 0x80, 0x00}, /*&quot;q&quot;,81*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0xFC, 0xFC, 0x10, 0x08, 0x04, 0x04, 0x0C, 0x0C, 0x00, 0x10, 0x10, 0x10, 0x1F, 0x1F, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00}, /*&quot;r&quot;,82*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x78, 0xCC, 0xC4, 0x84, 0x84, 0x84, 0x0C, 0x1C, 0x00, 0x00, 0x00, 0x1E, 0x18, 0x10, 0x10, 0x10, 0x11, 0x19, 0x0F, 0x06, 0x00}, /*&quot;s&quot;,83*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0xFF, 0xFF, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x10, 0x10, 0x10, 0x0C, 0x00, 0x00}, /*&quot;t&quot;,84*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFE, 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x1F, 0x18, 0x10, 0x10, 0x08, 0x1F, 0x0F, 0x08, 0x00}, /*&quot;u&quot;,85*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0C, 0x3C, 0xFC, 0xC4, 0x00, 0x00, 0xC4, 0x3C, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x1E, 0x0E, 0x01, 0x00, 0x00, 0x00}, /*&quot;v&quot;,86*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x3C, 0xFC, 0xC4, 0x00, 0xE4, 0x7C, 0xFC, 0x84, 0x80, 0x7C, 0x04, 0x00, 0x00, 0x07, 0x1F, 0x07, 0x00, 0x00, 0x07, 0x1F, 0x07, 0x00, 0x00}, /*&quot;w&quot;,87*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x1C, 0x7C, 0xE4, 0xC0, 0x34, 0x1C, 0x04, 0x04, 0x00, 0x00, 0x10, 0x10, 0x1C, 0x16, 0x01, 0x13, 0x1F, 0x1C, 0x18, 0x10, 0x00}, /*&quot;x&quot;,88*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0C, 0x3C, 0xFC, 0xC4, 0x00, 0xC4, 0x3C, 0x04, 0x04, 0x00, 0x00, 0x00, 0xC0, 0x80, 0xC1, 0x37, 0x0E, 0x01, 0x00, 0x00, 0x00, 0x00}, /*&quot;y&quot;,89*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x04, 0x04, 0xC4, 0xF4, 0x7C, 0x1C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1C, 0x1F, 0x17, 0x11, 0x10, 0x10, 0x18, 0x0E, 0x00}, /*&quot;z&quot;,90*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x60, 0x40, 0x00, 0x00}, /*&quot;{&quot;,91*/
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;|&quot;,92*/
    {0x00, 0x00, 0x04, 0x0C, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*&quot;}&quot;,93*/
    {0x00, 0x18, 0x06, 0x02, 0x02, 0x04, 0x08, 0x10, 0x20, 0x20, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    /*&quot;~&quot;,94*/                                                                                                                                                                                                                /*&quot;~&quot;,94*/
};

const ASCIIFont afont24x12 = {
    .h=24,
    .w=12,
    .chars=(unsigned char *)ascii_24x12,
};


const uint8_t chm_qwqData[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 
0x00, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0x7c, 0x7c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 
0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0x9f, 0x9f, 0x9f, 0x3f, 0x7f, 0xff, 0xff, 0x78, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x01, 0xfc, 0xfc, 0xfc, 0xf9, 0xf9, 0xe6, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 
0x80, 0x80, 0xe0, 0xe0, 0xf8, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x1c, 0x1c, 
0x11, 0x07, 0x07, 0x04, 0x04, 0x1c, 0x1c, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfb, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 
0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0x21, 0x63, 0xff, 0xff, 0x3f, 0x3f, 0xe7, 0xe7, 0xff, 0x27, 0x27, 0xe1, 0xe1, 0xff, 
0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x30, 0x31, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x27, 0x27, 0x27, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x04, 0x01, 0x03, 0x07, 
0x27, 0x27, 0x24, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x24, 0x24, 0x04, 0x04, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};
const Image chm_qwqImg = {64, 64, chm_qwqData};


uint32_t CNToInt32(const char *cn , uint8_t utf8le){
    uint32_t ret = 0;
    if(utf8le){ ret |= ((uint32_t)(cn[0]) &amp;lt;&amp;lt; 24); utf8le--; }
    if(utf8le){ ret |= ((uint32_t)(cn[1]) &amp;lt;&amp;lt; 16); utf8le--; }
    if(utf8le){ ret |= ((uint32_t)(cn[2]) &amp;lt;&amp;lt; 8); utf8le--; }
    if(utf8le) ret |= ((uint32_t)(cn[3])); 
	return ret;
} 

static uint8_t HashF(uint32_t x){
	x ^= x &amp;gt;&amp;gt; 16; x *= 0x45d9f3b; x ^= x &amp;gt;&amp;gt; 16;
	return (uint8_t)(x &amp;amp; (HASH_MAP_SIZE - 1));
}

static void Hash_Init(HashMap *hs){ memset(hs , 0 , sizeof(HashMap)); }

static bool HashError;
uint8_t HashFind(HashMap *hs , uint32_t x){
    HashError = false;
	uint8_t ret = HashF(x);
    for(uint8_t i = 0;i &amp;lt; HASH_MAP_SIZE;i++){
        if(!hs -&amp;gt; hav[ret]){ HashError = true; return ret; }//未找到
        if(hs -&amp;gt; key[ret] == x) return ret;
        ret = (ret + 1) &amp;amp; (HASH_MAP_SIZE - 1);
    }
	HashError = true; return 0; //满了
}

uint8_t HashState(HashMap *hs , uint8_t ret){
    if(!HashError) return 0;
    if(hs -&amp;gt; hav[ret]) return 1; //满
    return 2; //无
}

uint8_t HashInsert(HashMap *hs , uint32_t x){
	uint8_t tmp = HashFind(hs , x);
    if(hs -&amp;gt; key[tmp] == x) return tmp;
    if(HashError &amp;amp;&amp;amp; hs -&amp;gt; hav[tmp]) return 0; //满了
    else HashError = false;
    uint8_t ret = HashF(x);
    while(hs -&amp;gt; hav[ret]) ret = (ret + 1) &amp;amp; (HASH_MAP_SIZE - 1);
    hs -&amp;gt; hav[ret] = true; hs -&amp;gt; key[ret] = x;
    return ret;
}

uint8_t HashGet(HashMap *hs , uint32_t x){
    uint8_t ret = HashFind(hs , x);
    if(HashError) return 0;
    return hs -&amp;gt; value[ret];
}

void LoadFont(const Font *font){
    Hash_Init(font -&amp;gt; hs);
    uint8_t le = (((font -&amp;gt; h + 7) / 8) * font -&amp;gt; w) + 4;
    for(uint8_t i = 0;i &amp;lt; font -&amp;gt; len;i++)
        font -&amp;gt; hs -&amp;gt; value[HashInsert(font -&amp;gt; hs , CNToInt32((const char*)&amp;amp;font -&amp;gt; chars[i * le] , 4))] = i;
}

const uint8_t zh16x16[][36] = {
/* 0 彩 */ {0xe5,0xbd,0xa9,0x00,0x00,0x14,0x64,0x04,0x0c,0xb2,0x02,0x23,0x1a,0x00,0x20,0x10,0x08,0x86,0x60,0x00,0x40,0x21,0x11,0x0d,0x03,0xff,0x05,0x09,0x11,0x80,0x84,0x42,0x21,0x10,0x0c,0x00,},
/* 1 虹 */ {0xe8,0x99,0xb9,0x00,0x00,0xf8,0x08,0xff,0x08,0xf8,0x00,0x04,0x04,0x04,0xfc,0x04,0x04,0x04,0x00,0x00,0x20,0x63,0x21,0x1f,0x11,0x19,0x70,0x40,0x40,0x40,0x7f,0x40,0x40,0x40,0x40,0x00,},
/* 2 猫 */ {0xe7,0x8c,0xab,0x00,0x40,0x22,0x14,0x08,0xf4,0x02,0x04,0xc4,0x5f,0x44,0xc4,0x44,0x5f,0xc4,0x04,0x00,0x08,0x44,0x82,0x41,0x3f,0x00,0x00,0xff,0x44,0x44,0x7f,0x44,0x44,0xff,0x00,0x00,}
};
HashMap zh16x16_hash;
const Font font16x16 = {.w =16, .h = 16, .chars = (const uint8_t *)zh16x16,.len = sizeof(zh16x16)/36, .ascii = &amp;amp;afont16x8 , .hs = &amp;amp;zh16x16_hash};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;font.h&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#ifndef INC_FONT_H_
#define INC_FONT_H_

#include &quot;stdint.h&quot;
#include &quot;string.h&quot;
#include &quot;stdbool.h&quot;

typedef struct ASCIIFont {
    uint8_t h;
    uint8_t w;
    uint8_t *chars;
} ASCIIFont;

extern const ASCIIFont afont8x6;
extern const ASCIIFont afont12x6;
extern const ASCIIFont afont16x8;
extern const ASCIIFont afont24x12;

#define HASH_MAP_SIZE  256  
typedef struct HashMap {
	bool hav[HASH_MAP_SIZE];
	uint32_t key[HASH_MAP_SIZE];
	uint8_t value[HASH_MAP_SIZE];
} HashMap;

typedef struct Font {
    uint8_t h;              // 字高度
    uint8_t w;              // 字宽度
    const uint8_t *chars;   // 字库 字库前4字节存储utf8编码 剩余字节存储字模数据
    uint8_t len;            // 字库长度 超过256则请改为uint16_t
    const ASCIIFont *ascii; // 缺省ASCII字体 当字库中没有对应字符且需要显示ASCII字符时使用
    HashMap *hs;
} Font;

extern const Font font16x16;

typedef struct Image {
    uint8_t w; 
    uint8_t h;          
    const uint8_t *data; 
} Image;

extern const Image chm_qwqImg;

uint8_t HashState(HashMap *hs , uint8_t ret);
uint32_t CNToInt32(const char *cn , uint8_t utf8le);
uint8_t HashFind(HashMap *hs , uint32_t x);
uint8_t HashInsert(HashMap *hs , uint32_t x);
uint8_t HashGet(HashMap *hs , uint32_t x);
void LoadFont(const Font *font);

#endif /* INC_FONT_H_ */
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>利用 cloudflare 搭建个人图床</title><link>https://qwq-senlin.cc.cd/post/cloudflare-r2-tu/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/cloudflare-r2-tu/</guid><description>使用 cloudflare+worker+PicList</description><pubDate>Mon, 06 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;为什么用cloudflare&lt;/h1&gt;
&lt;p&gt;优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每月 10GB 存储 + 1000万次读取，根本用不完。&lt;/li&gt;
&lt;li&gt;零流量费用，一定程度上能防止被刷流量。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;速度不及国内服务商。&lt;/li&gt;
&lt;li&gt;要绑定信用卡，可能不太安全。。&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;获取部分&lt;/h1&gt;
&lt;h2&gt;1. 创建 cloudflare r2 存储桶&lt;/h2&gt;
&lt;p&gt;直接创建就好了，名字顺便填，下面记为 &lt;code&gt;r2-name&lt;/code&gt; ，地区选择亚太地区。&lt;/p&gt;
&lt;p&gt;然后就可以拖动上传一张照片试试了。&lt;/p&gt;
&lt;h2&gt;2. 创建 worker 处理&lt;/h2&gt;
&lt;p&gt;直接创建 worker，选择从 hello world 开始，名字顺便。&lt;/p&gt;
&lt;p&gt;点编辑代码，全选替换为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const referer = request.headers.get(&apos;Referer&apos;);
    const allowedDomains = [// 允许访问的域名列表
      &apos;baidu.com&apos; //要改
    ];
    let isAllowed = !referer;// 检查 Referer 是否在允许列表中
    if (referer) {// 检查 Referer 是否包含允许的域名
      for (const domain of allowedDomains) {
        if (referer.includes(domain)) {
          isAllowed = true;
          break;
        }
      }
    }
    if (!isAllowed) { // 如果不允许访问（直接访问或其他网站引用）
      // 返回防盗链提示图，建议直接返回文字，不然会占请求 B 类的次数
      // const warningImage = await env.MY_BUCKET.get(&apos;hotlink-warning.webp&apos;);
      // if (warningImage) {
      //   const headers = new Headers();
      //   headers.set(&apos;Content-Type&apos;, &apos;image/jpeg&apos;); // 如果是 PNG 改为 image/png
      //   headers.set(&apos;Cache-Control&apos;, &apos;public, max-age=3600&apos;); // 缓存1小时
      //   headers.set(&apos;X-Robots-Tag&apos;, &apos;noindex&apos;);
      //   return new Response(warningImage.body, {
      //     status: 200,
      //     headers
      //   });
      // }
      // 如果提示图不存在，返回文字提示
      return new Response(&apos;Hotlinking is not allowed.&apos;, {
        status: 403,
        headers: {
          &apos;Content-Type&apos;: &apos;text/plain&apos;,
          &apos;X-Robots-Tag&apos;: &apos;noindex&apos;
        }
      });
    }
    const userAgent = request.headers.get(&apos;User-Agent&apos;) || &apos;&apos;;
	const blockedUA = [&apos;curl&apos;, &apos;python-requests&apos;, &apos;Go-http-client&apos;, &apos;java&apos;];
	if (blockedUA.some(bad =&amp;gt; userAgent.toLowerCase().includes(bad))) {
	  return new Response(&apos;Forbidden: Bot not allowed&apos;, { status: 403 });
	}
    // 从 R2 获取文件
    const objectKey = url.pathname.slice(1); // 去掉开头的 /
    // 如果路径为空，返回提示
    if (!objectKey) {
      return new Response(&apos;R2 Image CDN - Please specify image path&apos;, {
        status: 400,
        headers: { &apos;Content-Type&apos;: &apos;text/plain&apos; }
      });
    }
    // 从 R2 获取对象
    const object = await env.MY_BUCKET.get(objectKey);
    if (object === null) {
      return new Response(&apos;Image Not Found&apos;, {
        status: 404,
        headers: { &apos;Content-Type&apos;: &apos;text/plain&apos; }
      });
    }
    // 设置响应头
    const headers = new Headers();
    object.writeHttpMetadata(headers);
    headers.set(&apos;etag&apos;, object.httpEtag);

    // 设置缓存
    headers.set(&apos;Cache-Control&apos;, &apos;public, max-age=5184000, immutable&apos;);

    // 设置 CORS（允许跨域）
    //headers.set(&apos;Access-Control-Allow-Origin&apos;, &apos;*&apos;); //

    // 返回图片
    return new Response(object.body, {
      headers
    });
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;点保存修改，再点右上角的部署。&lt;/p&gt;
&lt;h2&gt;3. 链接 r2&lt;/h2&gt;
&lt;p&gt;到 worker - 绑定 - R2 存储桶（&lt;strong&gt;如果没有按 CTRL+F5 刷新一下&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;变量名称填 &lt;code&gt;MY_BUCKET&lt;/code&gt; ，R2 存储桶选你创建的那个 &lt;code&gt;r2-name&lt;/code&gt; ，点部署。&lt;/p&gt;
&lt;h2&gt;4. 设置域名&lt;/h2&gt;
&lt;p&gt;点设置 - 域和路由 - 添加。&lt;/p&gt;
&lt;p&gt;输入你的域名就可以了。&lt;/p&gt;
&lt;h2&gt;5. 测测&lt;/h2&gt;
&lt;p&gt;假如你的存储库中有 123.webp 的一张图片，在浏览器输入 &lt;code&gt;&amp;lt;你的域名&amp;gt;/123.webp&lt;/code&gt; ，若出现 &lt;code&gt;Hotlinking is not allowed.&lt;/code&gt; 就成功了。&lt;/p&gt;
&lt;h1&gt;上传部分&lt;/h1&gt;
&lt;h2&gt;r2 token&lt;/h2&gt;
&lt;p&gt;R2 - 创建 Account API 令牌&lt;/p&gt;
&lt;p&gt;名称随便，权限是对象读和写，指定你创建的那个桶，时间永久。然后点创建。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一定要保存好令牌值，访问密钥 ID，Endpoint 和机密访问密钥！！！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一定要保存好令牌值，访问密钥 ID，Endpoint 和机密访问密钥！！！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;一定要保存好令牌值，访问密钥 ID，Endpoint 和机密访问密钥！！！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;只显示一次。或者建议不要关掉这个页面。&lt;/p&gt;
&lt;h2&gt;PicList&lt;/h2&gt;
&lt;p&gt;这里使用的是 &lt;a href=&quot;https://github.com/Kuingsmile/PicList/releases&quot;&gt;PicList&lt;/a&gt; ，下载不说。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://img.qwq-senlin.cc.cd/2026/04/3f3e31ceb05053ce8d5c7c6f9469e2b3.webp&quot; alt=&quot;350&quot; /&gt;&lt;/p&gt;
&lt;p&gt;打开 图床 - AWS S3。&lt;/p&gt;
&lt;p&gt;前面的把获取的那些东西填进去就好了。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;region 填 auto&lt;/li&gt;
&lt;li&gt;设置自定义节点：&lt;code&gt;你的账号ID.r2.cloudflarestorage.com&lt;/code&gt;（无 https）&lt;/li&gt;
&lt;li&gt;设置自定义域名：&lt;code&gt;https://你的域名&lt;/code&gt;（有 https）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;点确定，设为默认&lt;/p&gt;
&lt;p&gt;然后就行了。&lt;/p&gt;
&lt;p&gt;注意防盗链可能会防住自己。。就是在本地编辑时看不了。，，，所以我就把防盗链改成无 referer 也可以。&lt;/p&gt;
</content:encoded></item><item><title>记一次洛谷pyhon爬虫</title><link>https://qwq-senlin.cc.cd/post/luogu-pa/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/luogu-pa/</guid><description>python 爬虫初尝试</description><pubDate>Sat, 28 Mar 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;每次都只能在家里的电脑才能更新博客，太不方便了，如果能在浏览器上动态更新就好了。但是这样需要云服务器，，，没钱。于是想了个逆天的方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在某博客网站上更新文章。&lt;/li&gt;
&lt;li&gt;在家里电脑设定程序定期爬取该网站的文章。&lt;/li&gt;
&lt;li&gt;更新。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;wa wa wa，太完美了吧。&lt;/p&gt;
&lt;p&gt;于是目标变成：爬取私有文章。&lt;/p&gt;
&lt;p&gt;于是就有了个前提：登录账号。&lt;/p&gt;
&lt;p&gt;一种简单的方式就是手动获取cookie，然后放进请求头里就可以了。但是这样不优雅，还要定期手动重新获取。&lt;/p&gt;
&lt;p&gt;第二种方案，就是模拟登录获取cookie。我选择这一种。&lt;/p&gt;
&lt;p&gt;首先可以用 F12 发现洛谷登录请求的流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;请求 &lt;code&gt;https://www.luogu.com.cn/auth/login&lt;/code&gt;（GET） ，似乎没什么用。&lt;/li&gt;
&lt;li&gt;在输入用户名后，请求 &lt;code&gt;https://www.luogu.com.cn/auth/login-methods?login=username&lt;/code&gt;（GET）。没看到返回的是啥。&lt;/li&gt;
&lt;li&gt;提交登录，&lt;code&gt;https://www.luogu.com.cn/do-auth/password&lt;/code&gt;（POST），要用户名密码和验证码。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;另外有趣的是，洛谷反爬机制挺强的，第一会通过 cookie 验证，错误是返回 set_cookie，然后设置成这个就行了，挺搞笑的。&lt;/p&gt;
&lt;p&gt;另一个是在请求登录时，发现请求头会多出两个：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;X-Requested-With : XMLHttpRequest，听说是用来表明是 AJAX 异步接口请求的。&lt;/li&gt;
&lt;li&gt;X-CSRF-TOKEN : .....，这个就麻烦了，查询了资料。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/shandianchengzi/p/18155350&quot;&gt;资料&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;找了半天都没找到这玩意在哪生成的，幸好有前人指路。首先应该不是在 URL 或请求头中，我没看到。&lt;/p&gt;
&lt;p&gt;哦！，就在网页的 html 里：&lt;code&gt;&amp;lt;meta name=&quot;csrf-token&quot; content=&quot;1774766584:XvhhVwI22HPNHDEKIAzL5n9j3EERx5qCFt5GGZrhafw=&quot;&amp;gt;&lt;/code&gt;
``&lt;/p&gt;
&lt;p&gt;？&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ python .\luogu.py
Hi agent, as you see, I am just a cute teapot. Wanna a cup of tea?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;问题不大，改下 headers 就行了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import re
response = requests.get(HOMEPAGE , headers = HEADERS)
csrf_token = re.search(r&apos;&amp;lt;meta name=&quot;csrf-token&quot; content=&quot;([^&quot;]+)&quot;&apos;, response.text).group(1)
print(csrf_token)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;嗯。&lt;/p&gt;
&lt;p&gt;然后按照流程模拟就行了：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./luogu-pa.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;最难的应该就结束了，然后扩展的话可以加一个验证码识别。这部分先搁一下，先把爬取文章实现了。&lt;/p&gt;
&lt;p&gt;这里找到一个洛谷 API 的 &lt;a href=&quot;%5Bhttps://hk.gh-proxy.org/https://github.com/0f-0b/luogu-api-docs/blob/release%5D(https://hk.gh-proxy.org/https://github.com/0f-0b/luogu-api-docs/blob/release)&quot;&gt;文档&lt;/a&gt;：&lt;/p&gt;
&lt;p&gt;按照上面的说明，编写代码，并自动更新文件信息。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;def get_blogs_list(session : requests.Session , user , page): #670766
    API = &quot;https://www.luogu.com.cn/api/blog/userBlogs&quot;
    blog_list = session.get(API , headers = HEADERS , params = {&quot;user&quot; : str(user) , &quot;page&quot; : page})
    return blog_list.json()

def pull_blog_md(session : requests.Session , id , path):
    API = &quot;https://www.luogu.com.cn/api/blog/detail/&quot;
    ret = session.get(API + id , headers = HEADERS).json()[&quot;data&quot;]
    title = ret[&quot;Title&quot;][4:]
    post_time = strftime(&quot;%Y-%m-%d&quot; , localtime(ret[&quot;PostTime&quot;]))
    content = ret[&quot;Content&quot;]
    _ = re.search(r&quot;\A```[\s\S]*?```&quot; , content)
    print(f&quot;拉取 {title}&quot;)
    if _ == None:
        print(f&quot;{title} 格式错误！&quot;)
        return False
    information = _.group()
    information = information[3:(len(information) - 3)]
    other = content[_.end():]
    with open(f&quot;{path}\\{title}.md&quot; , &quot;w&quot; , encoding = &quot;utf-8&quot;) as f:
        f.write(&quot;---&quot;)
        f.write(information)
        f.write(f&quot;published: {post_time}\npubDate: {post_time}\ndate: {post_time}\ntitle: {title}\n---&quot;)
        f.write(other)
    print(f&quot;拉取 {title} 成功！&quot;)
    return True

def pull_context(session : requests.Session , user_id , path):
    now_page = 1
    while True:
        blog_list = get_blogs_list(session , user_id , now_page)[&quot;blogs&quot;][&quot;result&quot;]
        if len(blog_list) == 0: break
        for i in blog_list:
            if i[&quot;title&quot;][:4] == &quot;blog&quot;:
                pull_blog_md(session , str(i[&quot;id&quot;]) , path)
        now_page += 1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;下一步可以把，拉取下来的存到 blog 的文件夹，在调用我之前写的更新程序，自动上传到 github。&lt;/p&gt;
&lt;p&gt;下面是我在洛谷上创建的测试文章：
&lt;img src=&quot;./context_in_luogu.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;爬虫可以爬取创建时间等，这部分我让程序自动帮我填写。剩下的我就照常写在文章开头。&lt;/p&gt;
&lt;p&gt;下面是爬取下来后的效果：&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;context_in_obsidian.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;嗯，挺好的。&lt;/p&gt;
&lt;p&gt;然后调用更新：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ python .\pull_from_luogu.py
Cookie 已加载
Cookie 有效性: True
当前 Cookie:  {&apos;__client_id&apos;: &apos;不给你看&apos;, &apos;_uid&apos;: &apos;670766&apos;}
拉取 &quot;测试测试&quot;
拉取 &quot;测试测试&quot; 成功！
$ python .\update_post.py
更新 &quot;测试测试&quot;
git ok.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;效果你们应该已经看到了。。&lt;/p&gt;
&lt;p&gt;剩下的还有一个问题，就是版本问题：
什么叫版本问题呢，就是目前我的文章应该有三个端：github，本地，还有洛谷。每次修改是要以哪个为准呢？
嗯，懒得搞了，反正就我自己用。。&lt;/p&gt;
&lt;p&gt;就这样吧。&lt;/p&gt;
&lt;p&gt;最后放下代码吧：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import requests , re , base64 , json
from time import localtime , strftime
from os import mkdir
from os.path import exists

USERID = 670766
SAVE_PATH = r&quot;D:\\notes\\blog\\&quot;

HOMEPAGE = &quot;https://www.luogu.com.cn/auth/login&quot;
CAPTCHA = &quot;https://www.luogu.com.cn/lg4/captcha&quot;
LOGIN = &quot;https://www.luogu.com.cn/do-auth/password&quot; #POST
LOGIN_METHODS = &quot;https://www.luogu.com.cn/auth/login-methods&quot;

COOKIE_FILE = &quot;luogu_cookie.json&quot;
PASSWORD_FILE = &quot;luogu_password.txt&quot;

HEADERS = {
    &quot;User-Agent&quot; : &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0&quot; , 
    &quot;Referer&quot; : &quot;https://www.luogu.com.cn/&quot; , 
    &quot;Origin&quot; : &quot;https://www.luogu.com.cn&quot; ,
    &quot;X-Requested-With&quot; : &quot;XMLHttpRequest&quot; , # AJAX 异步接口请求
}

def save_cookie(session: requests.Session):
    with open(COOKIE_FILE , &quot;w&quot; , encoding = &quot;utf-8&quot;) as f:
        json.dump(requests.utils.dict_from_cookiejar(session.cookies) , f , indent = 2)
    print(&quot;Cookie 已保存&quot;)

def load_cookie(session: requests.Session):
    with open(COOKIE_FILE , &quot;r&quot;, encoding = &quot;utf-8&quot;) as f:
        session.cookies.update(json.loads(f.read()))
    print(&quot;Cookie 已加载&quot;)

def check_cookie_valid(session: requests.Session):
    check_url = &quot;https://www.luogu.com.cn/user/setting&quot;
    resp = session.get(check_url, headers = HEADERS , allow_redirects=False)
    valid = resp.status_code == 200
    print(f&quot;Cookie 有效性: {&apos;True&apos; if valid else &apos;False&apos;}&quot;)
    return valid

def login(session: requests.Session):
    LG_HEADERS = {
        &quot;User-Agent&quot; : &quot;Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:148.0) Gecko/20100101 Firefox/148.0&quot; , 
        &quot;Referer&quot; : &quot;https://www.luogu.com.cn/&quot; , 
        &quot;X-Requested-With&quot; : &quot;XMLHttpRequest&quot; ,
        &quot;Host&quot; : &quot;www.luogu.com.cn&quot; ,
    }

    response = session.get(HOMEPAGE , headers = LG_HEADERS , allow_redirects = True)
    csrf_token = re.search(r&apos;&amp;lt;meta name=&quot;csrf-token&quot; content=&quot;([^&quot;]+)&quot;&apos;, response.text).group(1)

    LG_HEADERS[&quot;X-CSRF-TOKEN&quot;] = csrf_token

    with open(PASSWORD_FILE , &quot;r&quot;) as f:
        USERNAME = base64.b64decode(f.readline()).decode()
        PASSWORD = base64.b64decode(f.readline()).decode()

    LG_HEADERS[&quot;Referer&quot;] = &quot;https://www.luogu.com.cn/auth/login&quot;
    login1 = session.get(LOGIN_METHODS , params = {&quot;login&quot; : USERNAME} , headers = LG_HEADERS)
    print(&quot;状态码：&quot; , login1.status_code)

    while True:
        captcha_image = session.get(CAPTCHA , headers = LG_HEADERS , allow_redirects = False).content
        with open(&quot;luogu_captcha.jpeg&quot; , &quot;wb&quot;) as f:
            f.write(captcha_image)
            f.flush()

        captcha = input(&quot;请查看并输入验证码：&quot;)[:4]
        print(captcha , len(captcha))

        data = {
            &quot;captcha&quot; : captcha , 
            &quot;password&quot; : PASSWORD ,
            &quot;username&quot; : USERNAME
        }

        # HEADERS[&quot;Content-Type&quot;] = &quot;application/json&quot;
        LG_HEADERS[&quot;Origin&quot;] = &quot;https://www.luogu.com.cn&quot;
        login2 = session.post(LOGIN , headers = LG_HEADERS , data = data , allow_redirects = False)
        print(&quot;状态码：&quot; , login2.status_code)

        if login2.status_code == 200:
            print(&quot;\033[32m登录成功\033[0m&quot;)
            save_cookie(session)
            return True
        elif login2.status_code == 400:
            print(&quot;\033[31m登录失败\003[0m，验证码错误：&quot;)
        elif login2.status_code == 401:
            print(&quot;\033[31m登录失败\033[0m，密码错误：&quot;)
        else:
            print(&quot;\033[31m登录失败\033[0m，其他错误：&quot;)
            print(login2.text)

def get_blogs_list(session : requests.Session , user , page): #670766
    API = &quot;https://www.luogu.com.cn/api/blog/userBlogs&quot;
    blog_list = session.get(API , headers = HEADERS , params = {&quot;user&quot; : str(user) , &quot;page&quot; : page})
    return blog_list.json()

def pull_blog_md(session : requests.Session , id , path):
    API = &quot;https://www.luogu.com.cn/api/blog/detail/&quot;
    ret = session.get(API + id , headers = HEADERS).json()[&quot;data&quot;]
    title = ret[&quot;Title&quot;][5:]
    post_time = strftime(&quot;%Y-%m-%d&quot; , localtime(ret[&quot;PostTime&quot;]))
    content = ret[&quot;Content&quot;]
    _ = re.search(r&quot;\A```[\s\S]*?```&quot; , content)
    if _ == None:
        print(f&quot;\033[31m格式错误！\033[0m： 跳过文章 \&quot;{title}\&quot;&quot;)
        return False
    information = _.group()
    information = information[3:(len(information) - 3)]
    other = content[_.end():]

    if not exists(f&quot;{path}\\{title}&quot;): mkdir(f&quot;{path}\\{title}&quot;)
    with open(f&quot;{path}\\{title}\\index.md&quot; , &quot;w&quot; , encoding = &quot;utf-8&quot;) as f:
        f.write(&quot;---&quot;)
        f.write(information)
        f.write(f&quot;published: {post_time}\npubDate: {post_time}\ndate: {post_time}\ntitle: {title}\n---&quot;)
        f.write(other)
    print(f&quot;\033[32m拉取成功！\033[0m：\&quot;{title}\&quot; 已更新！&quot;)
    return True

def pull_context(session : requests.Session , user_id , path):
    now_page = 1
    while True:
        blog_list = get_blogs_list(session , user_id , now_page)[&quot;blogs&quot;][&quot;result&quot;]
        if len(blog_list) == 0: break
        for i in blog_list:
            if i[&quot;title&quot;][:4] == &quot;blog&quot;:
                pull_blog_md(session , str(i[&quot;id&quot;]) , path)
        now_page += 1

if __name__ == &quot;__main__&quot;:
    session = requests.Session()
    load_cookie(session)
    if not check_cookie_valid(session):
        session.cookies.clear()
        login(session)
    print(&quot;当前 Cookie: &quot; , requests.utils.dict_from_cookiejar(session.cookies))
    print(&quot;开始拉取：\n&quot;)
    pull_context(session , USERID , SAVE_PATH)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>NOIP2025 简略题解</title><link>https://qwq-senlin.cc.cd/post/NOIP2025-tj/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/NOIP2025-tj/</guid><description>非人</description><pubDate>Mon, 01 Dec 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;我会永远记住这一天。&lt;/p&gt;
&lt;p&gt;update on 2026.6.28：现在忘了，，，&lt;/p&gt;
&lt;p&gt;我们不难注意到：&lt;strong&gt;noip2025=noi plus 2025&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;P14636 NOIP2025 T2&lt;/h1&gt;
&lt;p&gt;第一步就没想到。&lt;/p&gt;
&lt;p&gt;按照性价比大到小排序后，发现取不到最大值的情况是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;选的最后一个 $w=1$（否则选取的一定是前缀，是最大的）。&lt;/li&gt;
&lt;li&gt;此时选的情况应该是：&lt;code&gt;...i222..(已选前缀)j222..(不选)k(选)...(钱花完了)&lt;/code&gt;，其中 $w_i=1,w_j=2,w_k=1$。&lt;/li&gt;
&lt;li&gt;解释一下就是，先一直选，选到只剩 $1$ 块钱了，跳过中间为 $2$ 的连续段，选后面的第一个 $1$ 。&lt;/li&gt;
&lt;li&gt;那么有可能不是最大的情况当且仅当：$a_i+a_k&amp;lt;a_j$，即可以通过把两个 $w=1$ 性价比最低的糖果换成一个性价比高的 $w=2$ 的糖果。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后排序 $a$，枚举 $i,j$，让 $w_i=1,w_j=2$，因此要满足 $a_i&amp;lt;a_j&amp;lt;2a_i$（满足 $i$ 性价比大于 $j$）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原价大于 $a_j$ 的，一定会选（$j$ 是必选前缀的后面第一个），这样的数有 $n-j$ 个。&lt;/li&gt;
&lt;li&gt;原价大于 $a_i$ 小于 $a_j$ 的，只有 $w=1$ 时会被选。&lt;/li&gt;
&lt;li&gt;原价大于 $\dfrac{a_j}{2}$ 小于 $a_i$ 的，如果 $w=1$，那么 $i,j$ 之间就不全是 $2$，所以，$w=2$。都不会被选。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么 $k$ 如何求？我们找到满足 $a_k+a_i&amp;lt;a_j$ 的最大的 $k_m$，下面证明满足条件。
$$ a_{k_m}+a_i&amp;lt;a_j&amp;lt;2a_i \to a_{k_m} &amp;lt; a_i$$&lt;/p&gt;
&lt;p&gt;所以 $2a_{k_m}&amp;lt;a_{k_m}+a_i&amp;lt;a_j$，即 $k_m$ 的性价比比 $j$ 低。&lt;/p&gt;
&lt;p&gt;那么，在 $k_m$ 及以前的 $a$ 都可能成为 $k$，这时，我们在前 $k_m$ 个中任意定价 $1,2$ 都满足要求，所以方案数是 $2^{k_m}$。&lt;/p&gt;
&lt;p&gt;在 $k_m$ 到 $i$ 之间都是确定的，方案数为 $1$。到此时剩余价钱为 $m-2$，此时问题变成：&lt;/p&gt;
&lt;p&gt;有 $j-i-1$ 个 zbj1 为 $0/1$，还有 $n-j$ 个 zbj2 为 $1/2$。满足所有 zbj 的总和为 $m-2$，求方案数。&lt;/p&gt;
&lt;p&gt;不难想到，把 zbj2 的先扣去 1，变为 $(1+0/1)$，此时相当于在 $n-i-1$ 中选出 $m-2-(n-j)$ 个数的方案数。所以方案数为 $\binom{m-n+j-2}{n-i-1}$。&lt;/p&gt;
&lt;p&gt;然后似乎就做完了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

const int MOD = 998244353;
int n , m;
struct Num {
	int a , i;
	inline bool operator &amp;lt; (const Num b){ if(a == b.a) return i &amp;lt; b.i; return a &amp;lt; b.a; }
}a[5005];
int pw[10005] , C[10005][10005];

inline void init(int N){
	pw[0] = 1; for(int i = 1;i &amp;lt;= N;i++) pw[i] = pw[i - 1] * 2LL % MOD;
	C[0][0] = 1;
	for(int i = 1;i &amp;lt;= N;i++){
		C[i][0] = 1;
		for(int j = 1;j &amp;lt;= i;j++)
			if((C[i][j] = C[i - 1][j] + C[i - 1][j - 1]) &amp;gt;= MOD)
				C[i][j] -= MOD;
	}
}

int main(void){
	int c , T; scanf(&quot;%d%d&quot; , &amp;amp;c , &amp;amp;T);
	init(10000);
	while(T--){
		scanf(&quot;%d%d&quot; , &amp;amp;n , &amp;amp;m);
		for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;a[i].a) , a[i].i = i;
		sort(a + 1 , a + 1 + n);
		int ans = 0;
		for(int i = 1;i &amp;lt;= n;i++){
			int km = 0;
			for(int j = i + 1;j &amp;lt;= n;j++){
				if(a[j].a &amp;gt;= (a[i].a &amp;lt;&amp;lt; 1)) break;
				while(km &amp;lt; i &amp;amp;&amp;amp; a[km + 1].a + a[i].a &amp;lt; a[j].a) km++;
				if(m - n + j &amp;lt; 2 || a[i].a == a[j].a) continue;
//				printf(&quot;%d %d %lld\n&quot; , i , j , 1LL * pw[km] * C[n - i - 1][m - n + j - 2] % MOD);
				if((ans += 1LL * pw[km] * C[n - i - 1][m - n + j - 2] % MOD) &amp;gt;= MOD)
					ans -= MOD;
			}
		}
		printf(&quot;%d\n&quot; , (pw[n] - ans + MOD) % MOD);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;P14638 NOIP2025 T4&lt;/h1&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std; 

char buf[1 &amp;lt;&amp;lt; 21] , *p1 , *p2;
#define GC (p1 == p2 &amp;amp;&amp;amp; (p2 = (p1 = buf) + fread(buf , 1 , 1 &amp;lt;&amp;lt; 21 , stdin) , p1 == p2)? EOF : *p1++)
inline long long read(){
	long long ret = 0; bool f = 0; char c = GC;
	while(c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos;){
		if(c == &apos;-&apos;) f = 1;
		c = GC;
	}
	while(c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos;){
		ret = ret * 10 + (c ^ 48);
		c = GC;
	}
	return f? -ret : ret;
}

int n , q; long long a[50005];

long long st[50005][20]; int lg[50005];

namespace baoli {
	void solve(int L , int R){
		unsigned long long output = 0;
		for(int i = 1;i &amp;lt;= n;i++){
			long long ans = -1e16;
			for(int l = 1;l &amp;lt;= i;l++) {
				int rl = max(i , L + l - 1) , rr = min(n , R + l - 1);
				if(rl &amp;gt; rr) continue;
				int le = lg[rr - rl + 1];
				ans = max(ans , max(st[rl][le] , st[rr - (1 &amp;lt;&amp;lt; le) + 1][le]) - a[l - 1]);
			}
			output ^= (unsigned long long)i * ans;
		}
		printf(&quot;%llu\n&quot; , output);
	}
}

namespace A {
	deque &amp;lt;pair &amp;lt;long long , int&amp;gt; &amp;gt; qu;
	
	long long ans[50005];
	
	void solve(int L , long long ans[50005]){
		while(!qu.empty()) qu.pop_back();
		for(int l = 1;l + L - 1 &amp;lt;= n;l++){
			int r = l + L - 1;
			while(!qu.empty() &amp;amp;&amp;amp; qu.front().second &amp;lt; l) qu.pop_front();
			while(!qu.empty() &amp;amp;&amp;amp; qu.back().first &amp;lt; a[r] - a[l - 1]) qu.pop_back();
			qu.push_back(make_pair(a[r] - a[l - 1] , r));
			ans[l] = qu.front().first;
			//a[r] - a[l - 1];
		}
		for(int i = n - L + 2;i &amp;lt;= n;i++){
			while(!qu.empty() &amp;amp;&amp;amp; qu.front().second &amp;lt; i) qu.pop_front();
			ans[i] = qu.front().first;
		}
	}
	
	void print(){
		unsigned long long output = 0;
		for(int i = 1;i &amp;lt;= n;i++) output ^= (unsigned long long)i * ans[i];
		printf(&quot;%llu\n&quot; , output);
	}
}

namespace B {
	long long ans[33][50005];
	long long qwq[50005][33][6];
	
	void init(){
		for(int i = 1;i &amp;lt;= 32;i++) A::solve(i , ans[i]);
		for(int i = 1;i &amp;lt;= n;i++) for(int j = 1;j &amp;lt;= 32;j++) qwq[i][j][0] = ans[j][i];
		for(int o = 1;o &amp;lt;= n;o++){
			for(int k = 1;k &amp;lt;= 5;k++) for(int i = 1;i + (1 &amp;lt;&amp;lt; k) &amp;lt;= 33;i++)
				qwq[o][i][k] = max(qwq[o][i][k - 1] , qwq[o][i + (1 &amp;lt;&amp;lt; (k - 1))][k - 1]);
		}
	}
	
	void solve(int L , int R){
		unsigned long long output = 0;
		for(int i = 1;i &amp;lt;= n;i++){
			int le = lg[R - L + 1];
			output ^= (unsigned long long)i * max(qwq[i][L][le] , qwq[i][R - (1 &amp;lt;&amp;lt; le) + 1][le]);
		}
		printf(&quot;%llu\n&quot; , output);
	}
}

namespace AB {
	long long tmp[50005] , ans[50005];
	void solve(int L , int R){
		for(int j = 1;j &amp;lt;= n;j++) ans[j] = -1e16;
		for(int i = L;i &amp;lt;= R;i++){
			A::solve(i , tmp);
			for(int j = 1;j &amp;lt;= n;j++) ans[j] = max(ans[j] , tmp[j]);
		}
		unsigned long long output = 0;
		for(int i = 1;i &amp;lt;= n;i++) output ^= (unsigned long long)i * ans[i];
		printf(&quot;%llu\n&quot; , output);
	}
}

int main(void){
	// freopen(&quot;query.in&quot; , &quot;r&quot; , stdin);
	// freopen(&quot;query.out&quot; , &quot;w&quot; , stdout);
	n = read();
	for(int i = 1;i &amp;lt;= n;i++) a[i] = read() + a[i - 1];
	for(int i = 1;i &amp;lt;= n;i++) st[i][0] = a[i];
	for(int i = 2;i &amp;lt;= n;i++) lg[i] = lg[i &amp;gt;&amp;gt; 1] + 1;
	for(int k = 1;k &amp;lt;= lg[n];k++) for(int i = 1;i + (1 &amp;lt;&amp;lt; k) - 1 &amp;lt;= n;i++)
		st[i][k] = max(st[i][k - 1] , st[i + (1 &amp;lt;&amp;lt; (k - 1))][k - 1]);	
	q = read();
	B::init();
	for(int _ = 1;_ &amp;lt;= q;_++){
		int L , R; L = read(); R = read();
		if(R &amp;lt;= 32){ B::solve(L , R); continue; }
		if(L == R){
			A::solve(L , A::ans); A::print();
			continue;
		}
		if(R - L &amp;lt;= 32){ AB::solve(L , R); continue; }
		baoli::solve(L , R);
	}
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以发现，如果把区间放到矩形上，查询相当于一个梯形。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;./image.webp&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;对于$i$ ，实际上是绿色线的移动，移动是 $O(n)$ 级别的。而红线是不变的。&lt;/p&gt;
&lt;p&gt;如果 $2L\ge R$，可以拆成平行于 $x$ 和平行于 $y$ 的两个平行四边形，直接用两个单调队列算，两个分别按 $l$ ，和 $r$ ，另一维可以用 st 表取区间最大值作为这个点的答案（特殊性质 D）。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
typedef long long ll;

char buf[1 &amp;lt;&amp;lt; 21] , *p1 , *p2;
#define GC (p1 == p2 &amp;amp;&amp;amp; (p2 = (p1 = buf) + fread(buf , 1 , 1 &amp;lt;&amp;lt; 21 , stdin) , p1 == p2)? EOF : *p1++)
inline int read(){
	int ret = 0; char c = GC; bool f = 0;
	while(c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos;){ if(c == &apos;-&apos;) f = 1; c = GC; }
	while(c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos;){
		ret = (ret &amp;lt;&amp;lt; 1) + (ret &amp;lt;&amp;lt; 3) + (c ^ 48);
		c = GC;
	} 
	return f? -ret : ret;
} 

int n , a[50005]; ll b[50005] , stmi[50005][20] , stmx[50005][20];

inline ll st_query(ll st[50005][20] , int l , int r){
	l = max(l , 1); r = min(r , n);
	if(l &amp;gt; r) return 1145141919810;
	int le = __lg(r - l + 1); return max(st[l][le] , st[r - (1 &amp;lt;&amp;lt; le) + 1][le]);
}

deque &amp;lt;pair &amp;lt;int , ll&amp;gt; &amp;gt; q;
ll ans[50005];
inline void solve1(int L , int R){
	while(!q.empty()) q.pop_back();
	for(int i = 1;i &amp;lt;= n;i++){
		while(!q.empty() &amp;amp;&amp;amp; q.front().first &amp;lt; i) q.pop_front();
		ll x = st_query(stmx , i + L - 1 , i + R - 1);
		if(x != 1145141919810){
			x -= b[i - 1];
			while(!q.empty() &amp;amp;&amp;amp; q.back().second &amp;lt; x) q.pop_back();
			q.push_back(make_pair(i + L - 1 , x));
		}
		if(!q.empty()) ans[i] = max(ans[i] , q.front().second);
	}
}

inline void solve2(int L , int R){
	while(!q.empty()) q.pop_back();
	for(int i = n;i &amp;gt;= 1;i--){
		while(!q.empty() &amp;amp;&amp;amp; q.front().first &amp;gt; i) q.pop_front();
		ll x = st_query(stmi , i - R + 1 , i - L + 1);
		if(x != 1145141919810){
			x += b[i];
			while(!q.empty() &amp;amp;&amp;amp; q.back().second &amp;lt; x) q.pop_back();
			q.push_back(make_pair(i - L + 1 , x));
		}
		if(!q.empty()) ans[i] = max(ans[i] , q.front().second);
	}
}

int main(void){
	n = read();
	for(int i = 1;i &amp;lt;= n;i++){
		a[i] = read();
		stmx[i][0] = b[i] = b[i - 1] + a[i];
		stmi[i][0] = -b[i - 1];
	}
	for(int k = 1;k &amp;lt;= __lg(n);k++) for(int i = 1;i + (1 &amp;lt;&amp;lt; k) - 1 &amp;lt;= n;i++)
		stmx[i][k] = max(stmx[i][k - 1] , stmx[i + (1 &amp;lt;&amp;lt; (k - 1))][k - 1]) , 
		stmi[i][k] = max(stmi[i][k - 1] , stmi[i + (1 &amp;lt;&amp;lt; (k - 1))][k - 1]);
	int T = read();
	while(T--){
		int L , R; L = read(); R = read();
		for(int i = 1;i &amp;lt;= n;i++) ans[i] = -1e16;
		//[l + L - 1 , L + R - 1]

		solve1(L , R); 
		solve2(L , R);

		// for(int i = 1;i &amp;lt;= n;i++) printf(&quot;%lld &quot; , ans[i]); putchar(&apos;\n&apos;);

		unsigned long long output = 0;
		for(int i = 1;i &amp;lt;= n;i++) output ^= (unsigned long long)i * ans[i];
		printf(&quot;%llu\n&quot; , output);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于任意情况，我们可以把询问按照 $[2^i,2^{i+1}-1]$ 拆成 $\log n$ 段，是两散+连续整段，这样每段都满足 $2L\ge R$，可以用上面的方法。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
typedef long long ll;

char buf[1 &amp;lt;&amp;lt; 21] , *p1 , *p2;
#define GC (p1 == p2 &amp;amp;&amp;amp; (p2 = (p1 = buf) + fread(buf , 1 , 1 &amp;lt;&amp;lt; 21 , stdin) , p1 == p2)? EOF : *p1++)
inline int read(){
	int ret = 0; char c = GC; bool f = 0;
	while(c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos;){ if(c == &apos;-&apos;) f = 1; c = GC; }
	while(c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos;){
		ret = (ret &amp;lt;&amp;lt; 1) + (ret &amp;lt;&amp;lt; 3) + (c ^ 48);
		c = GC;
	} 
	return f? -ret : ret;
} 

int n , a[50005]; ll b[50005] , stmi[50005][20] , stmx[50005][20];

inline ll st_query(ll st[50005][20] , int l , int r){
	l = max(l , 1); r = min(r , n);
	if(l &amp;gt; r) return 1145141919810;
	int le = __lg(r - l + 1); return max(st[l][le] , st[r - (1 &amp;lt;&amp;lt; le) + 1][le]);
}

struct QWQ_Deque{
	int st , ed;
	pair &amp;lt;int , ll&amp;gt; _q[50005];
	inline void clear(){ st = 1; ed = 0; }
	inline void push_back(pair &amp;lt;int , ll&amp;gt; x){ _q[++ed] = x; }
	inline bool empty(){ return st &amp;gt; ed; }
	inline void pop_back(){ ed--; }
	inline void pop_front(){ st++; }
	inline pair &amp;lt;int , ll&amp;gt; back(){ return _q[ed]; }
	inline pair &amp;lt;int , ll&amp;gt; front(){ return _q[st]; }
}q;

ll ans[50005];
inline void solve1(int L , int R){
	q.clear();
	for(int i = 1;i &amp;lt;= n;i++){
		while(!q.empty() &amp;amp;&amp;amp; q.front().first &amp;lt; i) q.pop_front();
		ll x = st_query(stmx , i + L - 1 , i + R - 1);
		if(x != 1145141919810){
			x -= b[i - 1];
			while(!q.empty() &amp;amp;&amp;amp; q.back().second &amp;lt; x) q.pop_back();
			q.push_back(make_pair(i + L - 1 , x));
		}
		if(!q.empty()) ans[i] = max(ans[i] , q.front().second);
	}
}

inline void solve2(int L , int R){
	q.clear();
	for(int i = n;i &amp;gt;= 1;i--){
		while(!q.empty() &amp;amp;&amp;amp; q.front().first &amp;gt; i) q.pop_front();
		ll x = st_query(stmi , i - R + 1 , i - L + 1);
		if(x != 1145141919810){
			x += b[i];
			while(!q.empty() &amp;amp;&amp;amp; q.back().second &amp;lt; x) q.pop_back();
			q.push_back(make_pair(i - L + 1 , x));
		}
		if(!q.empty()) ans[i] = max(ans[i] , q.front().second);
	}
}

int main(void){
	n = read();
	for(int i = 1;i &amp;lt;= n;i++){
		a[i] = read();
		stmx[i][0] = b[i] = b[i - 1] + a[i];
		stmi[i][0] = -b[i - 1];
	}
	for(int k = 1 , _ = __lg(n);k &amp;lt;= _;k++) for(int i = 1;i + (1 &amp;lt;&amp;lt; k) - 1 &amp;lt;= n;i++)
		stmx[i][k] = max(stmx[i][k - 1] , stmx[i + (1 &amp;lt;&amp;lt; (k - 1))][k - 1]) , 
		stmi[i][k] = max(stmi[i][k - 1] , stmi[i + (1 &amp;lt;&amp;lt; (k - 1))][k - 1]);
	int T = read();
	while(T--){
		int L , R; L = read(); R = read();
		for(int i = 1;i &amp;lt;= n;i++) ans[i] = -1e16;
		//[l + L - 1 , L + R - 1]

		for(int i = 0 , _ = __lg(R);i &amp;lt;= _;i++){
			int l = (1 &amp;lt;&amp;lt; i) , r = (1 &amp;lt;&amp;lt; (i + 1)) - 1; r = min(r , n);
			if(l &amp;gt; R || r &amp;lt; L) continue;
			l = max(l , L); r = min(r , R);
			solve1(l , r); solve2(l , r);
			// if(L &amp;lt;= l &amp;amp;&amp;amp; r &amp;lt;= R){
			// }
			// else{

			// }
		}

		// for(int i = 1;i &amp;lt;= n;i++) printf(&quot;%lld &quot; , ans[i]); putchar(&apos;\n&apos;);

		unsigned long long output = 0;
		for(int i = 1;i &amp;lt;= n;i++) output ^= (unsigned long long)i * ans[i];
		printf(&quot;%llu\n&quot; , output);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;优化可以散段上面方法暴力做，整段预处理+st 表区间查询，可以做到 $O(nq)$。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
typedef long long ll;

char buf[1 &amp;lt;&amp;lt; 23] , *p1 , *p2;
#define GC (p1 == p2 &amp;amp;&amp;amp; (p2 = (p1 = buf) + fread(buf , 1 , 1 &amp;lt;&amp;lt; 23 , stdin) , p1 == p2)? EOF : *p1++)
inline int read(){
	int ret = 0; char c = GC; bool f = 0;
	while(c &amp;lt; &apos;0&apos; || c &amp;gt; &apos;9&apos;){ if(c == &apos;-&apos;) f = 1; c = GC; }
	while(c &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; c &amp;lt;= &apos;9&apos;){
		ret = (ret &amp;lt;&amp;lt; 1) + (ret &amp;lt;&amp;lt; 3) + (c ^ 48);
		c = GC;
	} 
	return f? -ret : ret;
} 

int n; ll b[50005] , chm[50005][16][5] , stmi[20][50005] , stmx[20][50005];

inline ll st_query(ll st[20][50005] , int l , int r){
	int le = __lg(r - l + 1); return max(st[le][l] , st[le][r - (1 &amp;lt;&amp;lt; le) + 1]);
};

int st , ed;
pair &amp;lt;int , ll&amp;gt; _q[50005];

ll ans[50005];
inline void solve(int L , int R){
	st = 1; ed = 0;
	for(int i = 1 , _ = n + 1 - L;i &amp;lt;= n;i++){
		while(st &amp;lt;= ed &amp;amp;&amp;amp; _q[st].first &amp;lt; i) st++;
		if(i &amp;lt;= _){
			ll x = st_query(stmx , i + L - 1 , min(i + R - 1 , n)) - b[i - 1];
			while(st &amp;lt;= ed &amp;amp;&amp;amp; _q[ed].second &amp;lt;= x) ed--;
			_q[++ed] = make_pair(i + L - 1 , x);
		}
		else if(st &amp;gt; ed) break;
		ans[i] = max(ans[i] , _q[st].second);
	}
	st = 1; ed = 0;
	for(int i = n;i &amp;gt;= 1;i--){
		while(st &amp;lt;= ed &amp;amp;&amp;amp; _q[st].first &amp;gt; i) st++;
		if(i &amp;gt;= L){
			ll x = b[i] + st_query(stmi , max(i - R + 1 , 1) , i - L + 1);
			while(st &amp;lt;= ed &amp;amp;&amp;amp; _q[ed].second &amp;lt;= x) ed--;
			_q[++ed] = make_pair(i - L + 1 , x);
		}
		else if(st &amp;gt; ed) break;
		ans[i] = max(ans[i] , _q[st].second);
	}
}

int main(void){
	n = read();
	for(int i = 1;i &amp;lt;= n;i++) {
		stmx[0][i] = b[i] = b[i - 1] + read();
		stmi[0][i] = -b[i - 1];
	}
	for(int k = 1 , _ = __lg(n);k &amp;lt;= _;k++) for(int i = 1;i + (1 &amp;lt;&amp;lt; k) - 1 &amp;lt;= n;i++)
		stmx[k][i] = max(stmx[k - 1][i] , stmx[k - 1][i + (1 &amp;lt;&amp;lt; (k - 1))]) , 
		stmi[k][i] = max(stmi[k - 1][i] , stmi[k - 1][i + (1 &amp;lt;&amp;lt; (k - 1))]);


	for(int i = 0 , _ = __lg(n);i &amp;lt;= _;i++){
		int l = (1 &amp;lt;&amp;lt; i) , r = (1 &amp;lt;&amp;lt; (i + 1)) - 1; r = min(r , n);
		for(int j = 1;j &amp;lt;= n;j++) ans[j] = -1e16;
		solve(l , r);
		for(int j = 1;j &amp;lt;= n;j++) chm[j][i][0] = ans[j];
	}
	
	for(int o = 1 , _ = __lg(n);o &amp;lt;= n;o++){
		for(int i = 0;i &amp;lt;= _ - 1;i++)
			chm[o][i][1] = max(chm[o][i][0] , chm[o][i + 1][0]);
		for(int i = 0;i &amp;lt;= _ - 3;i++)
			chm[o][i][2] = max(chm[o][i][1] , chm[o][i + 2][1]);
		for(int i = 0;i &amp;lt;= _ - 7;i++)
			chm[o][i][3] = max(chm[o][i][2] , chm[o][i + 4][2]);
		for(int i = 0;i &amp;lt;= _ - 15;i++)
			chm[o][i][4] = max(chm[o][i][3] , chm[o][i + 8][3]);
	}

	int T = read() , L , R;
	while(T--){
		L = read(); R = read();
		for(int i = 1;i &amp;lt;= n;i++) ans[i] = -1e16;

		int fszl = n , fszr = 0;
		for(int i = 0 , _ = __lg(R);i &amp;lt;= _;i++){
			int l = (1 &amp;lt;&amp;lt; i) , r = (1 &amp;lt;&amp;lt; (i + 1)) - 1; r = min(r , n);
			if(l &amp;gt; R || r &amp;lt; L) continue;
			if(L &amp;lt;= l &amp;amp;&amp;amp; r &amp;lt;= R)
				fszl = min(fszl , i) , fszr = max(fszr , i);
			else{
				l = max(l , L); r = min(r , R);
				solve(l , r);
			}
		}

		// printf(&quot;%d %d\n&quot; , fszl , fszr);
		if(fszl &amp;lt; n) for(int i = 1 , _ = __lg(fszr - fszl + 1) , __ = fszr - (1 &amp;lt;&amp;lt; _) + 1;i &amp;lt;= n;i++)
			ans[i] = max(ans[i] , max(chm[i][fszl][_] , chm[i][__][_]));

		// for(int i = 1;i &amp;lt;= n;i++) printf(&quot;%lld &quot; , ans[i]); putchar(&apos;\n&apos;);

		unsigned long long output = 0;
		for(int i = 1;i &amp;lt;= n;i++) output ^= (unsigned long long)i * ans[i];
		printf(&quot;%llu\n&quot; , output);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;卡常：st 表要注意内存的连续访问。&lt;/p&gt;
</content:encoded></item><item><title>CSP2025</title><link>https://qwq-senlin.cc.cd/post/poem-csp2025/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/poem-csp2025/</guid><description>短诗</description><pubDate>Sun, 02 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt; 
又一年csp，还是凉风袭面。
 
考场换了几度，终还是回到了厦一。&lt;/p&gt;
&lt;p&gt;校园还是记忆里的校园，可故友却相离不见。&lt;/p&gt;
&lt;p&gt;或偶遇旧识，却时间短暂，只得乘电梯来到考场。&lt;/p&gt;
&lt;p&gt; 
楼层不高，看得却较名楼高山更远更清。&lt;/p&gt;
&lt;p&gt;座椅老旧，坐上却在心间浮现别番味道。&lt;/p&gt;
&lt;p&gt; 
茫然离开时，不见红日。待结果倚栏风吹，闻后辈兴奋讨论，忽似又回到那年。
 
人来，人去，此时留下的还有多少？&lt;/p&gt;
&lt;p&gt;但流年逝水从不为任何人暂留，再次追忆起的那番欢乐却愈发苦涩。
 
又过一年csp，几人继续前行，几人落幕离场。
 &lt;/p&gt;
</content:encoded></item><item><title>锐评</title><link>https://qwq-senlin.cc.cd/post/some-comment/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/some-comment/</guid><description>一些评论</description><pubDate>Mon, 01 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;语文作文&lt;/h1&gt;
&lt;h2&gt;未来总是甜的&lt;/h2&gt;
&lt;p&gt;信息时代，要学的新知识和要解决的新问题越来越多。作为新时代少年，累一点再累一点，苦一点再苦一点，付出的心血和汗水多一点再多一点，都没关系，因为未来总是甜的。&lt;/p&gt;
&lt;p&gt;请以《未来总是甜的》作文。&lt;/p&gt;
&lt;p&gt;看到这个作文题便有一种很奇怪的感觉，像成功人士的居高立判，像理想主义的虚无宣言。未来总是甜的，可真总是甜的吗？看起来的阳光大道，实际上却是数以万计的人在窄木桥上挤破身心，那些上岸的人发表“未来总是甜”的宣言，而那些掉下的人又只能在生活的阴暗面挣扎。看来国之未来为甜，可个人的未来却不尽然。&lt;/p&gt;
&lt;p&gt;在我看来，（初中）作文题大多有个通病：沉迷在空想的乌托邦，和现实偏离甚远。什么“坚持带来成功（常见论点）”，“梦想与现实间的桥梁是努力（政治）”。&lt;/p&gt;
&lt;p&gt;成功学的灌输，却成了孔乙己的长衫。失败都是不够努力吗，成功都是因为奋斗吗？是的，在这种理念下，越来越多的人躲进了象牙塔。&lt;/p&gt;
&lt;p&gt;我们应该明确：坚持的意义不在于成功，而是在于本身。&lt;/p&gt;
&lt;p&gt;曾笑西西弗斯傻，但在机械地写完作文后，我竟然也成了西西弗斯。&lt;/p&gt;
&lt;p&gt;未来似乎变得扑朔迷离起来，可是，难道我们是因为未来是甜的而努力，而不是为了未来是甜的而努力吗？&lt;/p&gt;
&lt;p&gt;（本人观点，颇有片面）&lt;/p&gt;
&lt;h2&gt;助人与自助&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;世界乒乓球运动因发展严重不均衡而险些被移出奥运大家庭。这也是一枝独秀的中国队
面临的危机。2009 年开始，中国主动为他国培养人才，比如，分享训练成果，吸引外籍选
手参加乒超联赛，派教练和运动员赴海外执教、打球，等等。中外选手的对决从此变得更精
彩了。但外国选手在一些国际大赛中战胜中国队，又引发了国人的担忧。中国乒协主席刘国
梁回应：“帮助对手进步，我们也会变得更强大。再说，国乒的底蕴和厚度是其他国家无法
超越的。”中国乒乓球在推动世界乒乓球运动发展的同时，也让自己始终站在世界之巅。
中国乒乓球的发展之道具有启示意义。请结合材料写一篇文章，谈谈你的感悟与思考。
要求：选准角度，确定立意，明确文体，自拟标题；不要套作，不得抄袭；不得泄露个
人信息；不少于 800 字。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;自助与助人（作文解析），呵呵。&lt;/p&gt;
&lt;p&gt;我从没看出什么助人与自助，只看到了自大与胆怯。打败自己打造的对手，拿着自己锻造的金牌。表面友好的援助，赛场尊严的践踏，参赛机会是抛给的，金牌是施舍的。只是“主角”虚伪的自大罢了。&lt;/p&gt;
&lt;p&gt;另一点则是看客：狂热地支持着擂台——可是没有对手——于是他们去扶持对手——赢了他们喝彩，输了呢？一片哗然。裹包容外衣却看不起对手，为打破巅峰却恐于他人胜利。这是爱国吗？也许这是“最有思想的口号爱国者”，“最伟大的自私功利者”吧。&lt;/p&gt;
&lt;p&gt;倘若感悟已经被确定，分为三六九等，那思考就变为了对出题人意图的猜测。到头来，反而空洞地呐喊，虚伪地高歌，用着“富有创新”的死板结构，而能拿着千人之血的高分。（仅本题而言）&lt;/p&gt;
&lt;h2&gt;顶端优势与侧芽生长&lt;/h2&gt;
&lt;p&gt;植物生长中普遍存在着“顶端优势”的现象：当主茎顶芽占据生长主导地位时，会通过分泌生长素等方式抑制侧芽萌发与生长。保留顶芽，维持顶端优势，可促使主干挺拔茁壮；合理修剪顶芽，解除侧芽抑制，会让植株形态更饱满。&lt;/p&gt;
&lt;p&gt;以此材料引起了你的哪些联想与思考？请联系当今青年的成长，写一篇文章。&lt;/p&gt;
&lt;p&gt;要求：选准角度，确定立意，明确文体，自拟标题；不要套作，不得抄袭；不得泄露个人信息；不少于800字。&lt;/p&gt;
&lt;h3&gt;文章之基&lt;/h3&gt;
&lt;p&gt;下面称该作文解析为「材料」，作文题为「文本」。&lt;/p&gt;
&lt;p&gt;首先不妨提炼一下这形式的空洞的文本。材料对于原题的定义是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“顶芽”：某种事物的核心部分。（如文本中” “顶芽”可象征青年成长中的核心目标、主导价值观或核心能力 “）&lt;/li&gt;
&lt;li&gt;”侧芽“：某种事物除去核心的可能性。（文本” “侧芽”则可以对应青年的多元潜能 “）&lt;/li&gt;
&lt;li&gt;”保留（顶芽）“：坚守核心。（类似 集中）&lt;/li&gt;
&lt;li&gt;”修剪（顶芽）“：不动顶芽，让顶芽不分泌生长素。（类似 并进）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;先总体地说，材料确实把文本中的一些”关键词“对应到了青年或比较好讲的地方——虽然倒有些像机械地编解码，寻找符合出题人的正确对应关系。可是这所谓的”正确“到底正确吗，凭什么正确呢（毕竟是出题人）？文学从来都应是开放的，而不是精确的。哦这是语文，不是文学。&lt;/p&gt;
&lt;p&gt;再一个一个定义提出一些微小的看法，为此，我先针对原题目提出一个简单的引理：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;引理：顶芽与侧芽在一定程度上是矛盾的，下面称之为「矛盾性」&lt;/p&gt;
&lt;p&gt;证明1：由于顶芽会抑制侧芽，侧芽的生长需修剪顶芽。也就是顶芽好时侧芽不好，侧芽好时顶芽不能好。于是植株并不能在顶芽保留的情况下，侧芽丛生。&lt;/p&gt;
&lt;p&gt;证明2：植物生长资源之有限，必无法实现”既要有要“。对应人精力有限。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;顶芽：没偏太远，但是与后文所提矛盾：
&lt;ol&gt;
&lt;li&gt;&quot; “修剪”什么？可能是过度的自我中心、固执己见、不必要的枝蔓（如不良习惯、分散精力的干扰因素）、对异见的排斥等。&quot;，请问这些算顶芽还是侧芽？这些是核心吗？要修改的不是顶芽吗？&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;侧芽：荒谬在畸形的辩证，这部分后文详细提及。”让核心与多元共生“：根据「矛盾性」，这是无法实现的。&lt;/li&gt;
&lt;li&gt;保留：原题中“保留顶芽，维持顶端优势”，材料仅注重前者，即坚定主线（利）；而后者代表者抑制侧芽（弊）。后者材料刻意忽略。&lt;/li&gt;
&lt;li&gt;修剪：还是根据原题中“合理修剪顶芽，解除侧芽抑制”，材料讲修剪直接定义为解除侧芽抑制，可是原题的逻辑应是“通过合理修剪顶芽，来解除侧芽抑制”，这里的前提就是顶芽被剪短。而材料直接粗暴地忽略弊处。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可见材料避重就轻，并美其名曰辩证法。下面我为辩证法正名。&lt;/p&gt;
&lt;h3&gt;行云之云&lt;/h3&gt;
&lt;p&gt;欲文章浑然天成行云流水，重要的它的词与词，句与句，段与段的逻辑。该材料试图让辩证法做这“非常正确”的文章的脊柱，即使它所谓的辩证法似颗枯木。&lt;/p&gt;
&lt;p&gt;材料反复强调“辩证关系”“平衡艺术”“主次相生”，可是 &lt;strong&gt;何时该保留，何时该修剪？这个度是什么？&lt;/strong&gt;，材料对此有冒充真理的空话：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“ “合理”的标准是什么？ 如何把握“修剪”的度，避免因过度修剪而失去主干，或因从不修剪而杂乱无章？这需要青年有自我反思和判断能力。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于文章总有个读者，也总有作者意图传达的对象。根据这句话，我们不难看出该材料是写给 &lt;strong&gt;即没有自我反思也没有判断能力的傻子青年&lt;/strong&gt; 的。&lt;/p&gt;
&lt;p&gt;于是，这个丑陋的材料妄图把所有可能都囊括进来（既要专注又要多元，既要聚焦又要全面），看似海纳百川般全面，实则比黑洞还空洞。真正的辩证思维需要具体情境下的判断标准，而非两头都占的“正确废话”。这种“什么都对”的解析，倒是让议论文最重要的价值判断力“羽化而登仙”了。&lt;/p&gt;
&lt;h3&gt;&quot;辩证&quot;谢幕&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;黑格尔说：“矛盾是一切运动和生命力的根源；事物只因为自身具有矛盾，它才会运动，才具有生命力”（提示：黑格尔系统性提出辩证法）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;辩证法的根源就在于矛盾，舍去了矛盾，只强硬地合，只会更加对立。顺便一提，黑格尔坚持反对抽象的同一性，认为是形式的，不真实的，具体的同一性必会矛盾于自身。&lt;/p&gt;
&lt;h1&gt;其他&lt;/h1&gt;
&lt;h2&gt;锐评初三演讲稿&lt;/h2&gt;
&lt;p&gt;写于，忘记了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;大家好！今天我站在这里，满怀激情地与大家分享一些关于学习经验的心得。学习，犹如一段跌宕起伏的旅程，我们都是其中的探索者，每个人都在努力寻找属于自己的学习之道。今天，我想和大家一起探讨一下如何在这段旅程中更加高效、更加生动地学习。&lt;/p&gt;
&lt;p&gt;首先，让我来给大家讲一个制定学习计划的英雄故事。我们都知道，英雄之所以能够战胜强大的敌人，都是因为他们有着周详的作战计划。同样地，我们学习也需要制定出一份属子自己的英雄计划，这样才能更好地征服知识的山峰。我们要根据自己的学习目标和时间安排，像英雄一样勇敢地分配学习时间，明确自己的学习目标，这样才能有针对性地进行学习。同时，我们还需要像英雄一样坚韧不拔地合理安排时间，避免拖延和浪费时间。&lt;/p&gt;
&lt;p&gt;接下来，我要分享给大家的是如何选择适合自己的学习方法。想象一下，我们在战场上，有的人擅长使用剑，有的人擅长使用弓箭，有的人则擅长使用计谋。学习也是一样的，我们需要根据自己的特点来选择适合自己的学习方法。有的人喜欢通过阅读来学习，有的人则更喜欢通过听课或做笔记来学习。我自己的经验是，像英雄一样多种学习方式相结合，可以提高学习效果。
此外，我认为在学习的战场上，积极参与课堂讨论和互动也是至关重要的。课堂是我们学习的重要场所，通过与老师和同学们的互动，我们可以更好地理解和掌握知识。在课堂上，我会像英雄一样积极参与讨论和提问，这样不仅可以提高自己的理解能力，还可以从他人的观点中得到启发和思考。&lt;/p&gt;
&lt;p&gt;最后，我想告诉大家，学习是一场持久战，我们需要具备坚持和毅力这两个英雄品质。有时候，我们会遇到困难和挫折，但只要我们保持积极的心态，像英雄一样坚持不懈地努力，就一定能够克服困难，取得学习的成功。&lt;/p&gt;
&lt;p&gt;总结起来，学习经验是一个充满奇遇的旅程，我们需要像英雄一样，拥有坚定的信念、合理的计划、独特的方法和无畏的勇气。希望我今天分享的经验能够点燃大家学习的激情，让我们一起在学习的旅程中，成为那个勇敢的、智慧的、坚持的英雄！&lt;/p&gt;
&lt;p&gt;谢谢大家!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;经典发言稿，经典鸡汤。这篇没有经过思考，只是胡乱组合词句的文章：“学习经验是一个充满奇遇的旅程”；经常使用不当类比的手法：学习与打仗哪来的可比性；它逻辑混乱：“根据学习目标....制定学习目标”；“像英雄一样勇敢地分配学习时间”，它觉得我们居然不敢分配时间。&lt;/p&gt;
&lt;p&gt;“学习的战场”，是的，学习在这里只是战场，学习经验是打仗策略，那么我们在跟谁打？这个教育游戏，其实是个零和博弈也说不定呢。&lt;/p&gt;
&lt;p&gt;他卓越的英雄论，像经典小资话术，像成功者的高下立判。仿佛自己是英雄？那有些自大了。引用我之前的一句话：「成功学的灌输，似成了孔乙己的长衫。但是失败都是因为不够努力吗？成功都只是靠奋斗吗？」&lt;/p&gt;
&lt;p&gt;他根本没经历过挫折，可笑的是，这个人后来经历挫折时居然选择了逃避。&lt;/p&gt;
&lt;p&gt;卑劣地“混入人群”，怕得罪任何人，于是只能得罪自己。表面的自大，却是自卑。&lt;/p&gt;
&lt;p&gt;我越来越不理解我。也许，单纯会更快乐吧。&lt;/p&gt;
</content:encoded></item><item><title>为什么说 dp 是恐怖的？</title><link>https://qwq-senlin.cc.cd/post/OI-dp/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/OI-dp/</guid><description>关于dp，你需要知道：</description><pubDate>Mon, 20 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;小编带你来了解下 dp：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/343e16kz&quot;&gt;https://www.luogu.com.cn/article/343e16kz&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://oi-wiki.org/dp/opt/slope-trick/&quot;&gt;https://oi-wiki.org/dp/opt/slope-trick/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/training/559292#information&quot;&gt;https://www.luogu.com.cn/training/559292#information&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/bn3a465i&quot;&gt;https://www.luogu.com.cn/article/bn3a465i&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/ki71nw88&quot;&gt;https://www.luogu.com.cn/article/ki71nw88&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://qalxry.github.io/2024/01/20/%E3%80%90%E7%AE%97%E6%B3%95%E3%80%91DP%E4%BC%98%E5%8C%96%E6%80%BB%E7%BB%93/&quot;&gt;https://qalxry.github.io/2024/01/20/%E3%80%90%E7%AE%97%E6%B3%95%E3%80%91DP%E4%BC%98%E5%8C%96%E6%80%BB%E7%BB%93/&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;结构&lt;/h1&gt;
&lt;h3&gt;树形 dp&lt;/h3&gt;
&lt;h4&gt;P2279 消防局的设立&lt;/h4&gt;
&lt;h5&gt;方法一&lt;/h5&gt;
&lt;p&gt;设 $ f_{i,0/1/2/3/4} $为以$ i $为子树，保证能点亮 下两层/下一层/自己/父亲/上二 及以下的所有节点 的最小代价。&lt;/p&gt;
&lt;p&gt;转移比较简单。&lt;/p&gt;
&lt;h5&gt;方法二&lt;/h5&gt;
&lt;p&gt;设$ f_{i,0/1/2/3/4} $为以$ i $为子树，存在$ i $的 下下层儿子/儿子/自己/父亲/往上距离为 2 的点将其点亮的最小代价。&lt;/p&gt;
&lt;p&gt;转移读者自行尝试，如果不会，可以去问连神，&lt;a href=&quot;https://www.luogu.com.cn/user/696174&quot;&gt;chm_qwq&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;虽然不知道和方法一有什么区别。&lt;/p&gt;
&lt;h5&gt;方法三&lt;/h5&gt;
&lt;p&gt;贪心，我们考虑在刚好能点亮的位置点灯。下面设$ D $为一个灯最远能点亮的距离。&lt;/p&gt;
&lt;p&gt;于是设$ g_{i} $为以$ i $为子树最远没有被点亮的距离；$ f_i $为以$ i $为子树最近被点亮的点的距离。&lt;/p&gt;
&lt;p&gt;根据定义有：$ g_i=\max_{i\in son_u} g_i+1 $，$ f_i=\min_{i\in son_u} f_i+1 $。&lt;/p&gt;
&lt;p&gt;于是分三种情况。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$ g_i+f_i \le D $：可以直接点亮，于是$ g_i=-inf $。&lt;/li&gt;
&lt;li&gt;如果这个点为必须点亮而没有被点亮，既$ f_i&amp;gt;D $，那么$ g_i=\max{0,g_i} $既要求其他点给这个点点亮。&lt;/li&gt;
&lt;li&gt;若$ g_i=D $到最远距离了，直接在该点放灯塔，那么$ g_i=-inf,f_i=0 $。&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;ex方法一/二&lt;/h5&gt;
&lt;p&gt;若在点$ i $放灯要代价$ a_i $。&lt;/p&gt;
&lt;p&gt;$ f_{i,j} $为以$ i $为子树，向上至少能点亮$ j $层的最小代价。&lt;/p&gt;
&lt;p&gt;$ g_{i,j} $为以$ j $为子树，向下至少能点亮$ j $层的最小代价。&lt;/p&gt;
&lt;p&gt;转移读者自推不难。&lt;/p&gt;
&lt;h2&gt;状压&lt;/h2&gt;
&lt;h3&gt;技巧&lt;/h3&gt;
&lt;h4&gt;枚举子集$ O(3^n) $&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;for(int T = (S - 1) &amp;amp; S;T;T = (T - 1) &amp;amp; S){
	//真子集要从S开始。
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;高维前缀和$ O(n 2^n) $&lt;/h4&gt;
&lt;h5&gt;子集&lt;/h5&gt;
&lt;p&gt;$ g(S)=\sum_{T\subseteq S} f(T) $&lt;/p&gt;
&lt;p&gt;eg：$ f_s $表示有几个满足 $ a_i \subseteq s $。&lt;/p&gt;
&lt;p&gt;维护有三种理解。&lt;/p&gt;
&lt;h6&gt;去重法&lt;/h6&gt;
&lt;p&gt;最简单的想法是去掉一个转移：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int j = 0;j &amp;lt; (1 &amp;lt;&amp;lt; n);j++)
    for(int i = 0;i &amp;lt; n;i++)
		if(j &amp;gt;&amp;gt; i &amp;amp; 1) f[i] += f[i ^ (1 &amp;lt;&amp;lt; j)];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然而会重，换枚举顺序即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int i = 0;i &amp;lt; n;i++)
	for(int j = 0;j &amp;lt; (1 &amp;lt;&amp;lt; n);j++)
		if(j &amp;gt;&amp;gt; i &amp;amp; 1) f[i] += f[i ^ (1 &amp;lt;&amp;lt; j)];
&lt;/code&gt;&lt;/pre&gt;
&lt;h6&gt;dp法&lt;/h6&gt;
&lt;p&gt;为了去重，我们设$ f_{i,s} $表示只允许右$ i $位可与$ s $不同（但是仍为$ s $的子集）的和。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$ f_{i,s}=f_{i-1,s}(i \not \in s) $&lt;/li&gt;
&lt;li&gt;$ f_{i,s}=f_{i-1,s} + f_{i-1,s \oplus 2^i}(i\in s) $&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将$ i $滚掉即可得到代码。&lt;/p&gt;
&lt;h6&gt;类比法&lt;/h6&gt;
&lt;p&gt;看三维前缀和：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int i = 1;i &amp;lt;= n;i++) for(int j = 1;j &amp;lt;= n;j++) for(int z = 1;z &amp;lt;= n;z++)
    f[i][j][z] += f[i - 1][j][z];
for(int i = 1;i &amp;lt;= n;i++) for(int j = 1;j &amp;lt;= n;j++) for(int z = 1;z &amp;lt;= n;z++)
    f[i][j][z] += f[i][j - 1][z];
for(int i = 1;i &amp;lt;= n;i++) for(int j = 1;j &amp;lt;= n;j++) for(int z = 1;z &amp;lt;= n;z++)
    f[i][j][z] += f[i][j][z - 1];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;若扩展到$ n $维也是如此。&lt;/p&gt;
&lt;p&gt;假如每维只有$ 2 $呢，那么$ f $就可以状压成$ f_s $，然后枚举每一位即可。&lt;/p&gt;
&lt;h5&gt;超集&lt;/h5&gt;
&lt;p&gt;$ g(S)=\sum_{S\subseteq T} f(T) $&lt;/p&gt;
&lt;p&gt;$ f_s $表示有几个满足 $ s \subseteq a_i $。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int i = 0;i &amp;lt; n;i++)
	for(int j = 0;j &amp;lt; (1 &amp;lt;&amp;lt; n);j++)
		if(!(j &amp;gt;&amp;gt; i &amp;amp; 1)) f[i] += f[i ^ (1 &amp;lt;&amp;lt; j)];
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;差分&lt;/h5&gt;
&lt;p&gt;差分回去的话，直接把加号改成减号。&lt;/p&gt;
&lt;h3&gt;&amp;lt;font style=&quot;color:rgba(0, 0, 0, 0.75);&quot;&amp;gt;P3959 &amp;lt;/font&amp;gt;宝藏&lt;/h3&gt;
&lt;p&gt;好题。核心技巧是枚举子集，妙处在状态设计。&lt;/p&gt;
&lt;p&gt;因为加路径需要到起点的距离，那么我们可以看成一滴水从某个顶点开始散开，一次性添加需要的同一层的所有点。&lt;/p&gt;
&lt;p&gt;于是我们先处理出$ f_{i,j} $表示当前点集为$ i $，扩展的点集为$ j $的最小路径长度和。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const int S = (1 &amp;lt;&amp;lt; n) - 1;
for(int i = 2;i &amp;lt;= S;i++) lg[i] = lg[i &amp;gt;&amp;gt; 1] + 1;
for(int i = 1;i &amp;lt;= S;i++){
    cnt = 0;
    for(int j = (S ^ i) , _ = (S ^ i);j;j = (j - 1) &amp;amp; _)
        tmp[++cnt] = j;
    for(int j = cnt;j &amp;gt;= 1;j--){
        int lowbit = (tmp[j] &amp;amp; -tmp[j]) , v = inf;
        for(int z = 0;z &amp;lt; n;z++) if(i &amp;gt;&amp;gt; z &amp;amp; 1) v = min(v , mp[lg[lowbit]][z]);
        f[i][tmp[j]] = add(f[i][tmp[j] ^ lowbit] , v); 
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后求出$ g_{i,j} $表示共有$ i $层，点集为$ j $，显然$ g_{i,j}=\sum_{s\in j} g_{i-1,j\oplus s}+f_{j\oplus s,j} $。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;

const int inf = 1e9;
int n , m;
int mp[20][20];
int f[4100][4100] , g[14][4100];
int lg[4100];
int tmp[4100] , cnt;

inline int add(int x , int y){ return (x &amp;gt; inf - y? inf : x + y); }
inline int mul(int x , int y){ return (x &amp;gt; inf / y? inf : x * y); }

int main(void){
	scanf(&quot;%d%d&quot; , &amp;amp;n , &amp;amp;m);
	memset(mp , 0x3f , sizeof(mp));
	memset(g , 0x3f , sizeof(g));
	while(m--){
		int u , v , w; scanf(&quot;%d%d%d&quot; , &amp;amp;u , &amp;amp;v , &amp;amp;w);
		u--; v--;
		mp[u][v] = min(mp[u][v] , w);
		mp[v][u] = min(mp[v][u] , w);
	}
	const int S = (1 &amp;lt;&amp;lt; n) - 1;
	for(int i = 2;i &amp;lt;= S;i++) lg[i] = lg[i &amp;gt;&amp;gt; 1] + 1;
	for(int i = 1;i &amp;lt;= S;i++){
		cnt = 0;
		for(int j = (S ^ i) , _ = (S ^ i);j;j = (j - 1) &amp;amp; _)
			tmp[++cnt] = j;
		for(int j = cnt;j &amp;gt;= 1;j--){
			int lowbit = (tmp[j] &amp;amp; -tmp[j]) , v = inf;
			for(int z = 0;z &amp;lt; n;z++) if(i &amp;gt;&amp;gt; z &amp;amp; 1) v = min(v , mp[lg[lowbit]][z]);
			f[i][tmp[j]] = add(f[i][tmp[j] ^ lowbit] , v); 
		}
	}
	// printf(&quot;%d\n&quot; , f[1][8]);
	for(int i = 0;i &amp;lt; n;i++) g[0][1 &amp;lt;&amp;lt; i] = 0;
	for(int k = 1;k &amp;lt; n;k++) for(int i = 1;i &amp;lt;= S;i++)
		for(int j = i;j;j = (j - 1) &amp;amp; i)
			g[k][i] = min(g[k][i] , add(g[k - 1][i ^ j] , mul(f[i ^ j][j] , k)));
	int ans = inf;
	for(int k = 0;k &amp;lt; n;k++) ans = min(ans , g[k][S]);
	printf(&quot;%d\n&quot; , ans);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&amp;lt;font style=&quot;color:rgba(0, 0, 0, 0.75);&quot;&amp;gt;P1357 &amp;lt;/font&amp;gt;花园&lt;/h3&gt;
&lt;p&gt;首先可以得：$ f_{i,j} $为前$ i $个花后$ m $个为$ j $的方案，转移显然。环可以看成有$ n+m $朵花，前后相同。&lt;/p&gt;
&lt;p&gt;然后发现$ f $均有前一状态转移而来，并且可转移的点相同，那么可以写成矩阵，矩阵快速幂优化即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
typedef long long ll;

const int MOD = 1e9 + 7;

ll n; int m , k , ans;

const int N = 32;
struct QWQ {
	int a[34][34];
	inline QWQ(){ memset(a , 0 , sizeof(a)); }
	inline friend QWQ operator * (const QWQ x , const QWQ y){
		QWQ ret;
		for(int i = 0;i &amp;lt; N;i++) for(int j = 0;j &amp;lt; N;j++)
			for(int k = 0;k &amp;lt; N;k++)
				if((ret.a[i][j] += (ll)x.a[i][k] * y.a[k][j] % MOD) &amp;gt;= MOD)
					ret.a[i][j] -= MOD;
		return ret;
	}
}base , qwq;

inline QWQ qpow(QWQ x , ll y){
	QWQ ret;
	for(int i = 0;i &amp;lt; N;i++) ret.a[i][i] = 1;
	while(y){
		if(y &amp;amp; 1) ret = ret * x;
		x = x * x; y &amp;gt;&amp;gt;= 1;
	}
	return ret;
}

int main(void){
	scanf(&quot;%lld%d%d&quot; , &amp;amp;n , &amp;amp;m , &amp;amp;k);
	const int S = (1 &amp;lt;&amp;lt; m) - 1;
	for(int j = 0;j &amp;lt;= S;j++){
		if(__builtin_popcount(j) &amp;gt; k) continue;
		base.a[(j &amp;lt;&amp;lt; 1) &amp;amp; S][j] = 1;
		if(__builtin_popcount((j &amp;lt;&amp;lt; 1 | 1) &amp;amp; S) &amp;lt;= k)
			base.a[(j &amp;lt;&amp;lt; 1 | 1) &amp;amp; S][j] = 1;
	}
	qwq = qpow(base , n);
	for(int s = 0;s &amp;lt;= S;s++) if(__builtin_popcount(s) &amp;lt;= k)
		if((ans += qwq.a[s][s]) &amp;gt;= MOD) ans -= MOD;
	printf(&quot;%d\n&quot; , ans);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;P5369 [PKUSC2018] 最大前缀和&lt;/h3&gt;
&lt;p&gt;难点在转换。&lt;/p&gt;
&lt;p&gt;考虑枚举可能的最大前缀和，显然有$ 2^n $种，对于每种合法的最大前缀和（前$ i $个为最大）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$ 1&amp;lt;j \le i $满足$ \sum_{k=j}^i a_k \ge 0 $。&lt;/li&gt;
&lt;li&gt;$ i &amp;lt; j \le n $满足$ \sum_{k=j}^i a_k &amp;lt; 0 $。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原因显然。发现前后并不冲突，于是可以分开dp。&lt;/p&gt;
&lt;p&gt;对于第一种，可以前插，条件是插入前的和大于等于 0。&lt;/p&gt;
&lt;p&gt;对于第二种，可以后插，条件是插入后的和小于 0。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

const int MOD = 998244353;
int n , f[1100005] , g[1100005];
long long sum[1100005];
//f：后缀和的真子集都大于等于0的方案数
//g：前缀和都小于0的方案数

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 0;i &amp;lt; n;i++) scanf(&quot;%lld&quot; , &amp;amp;sum[1 &amp;lt;&amp;lt; i]);
	const int S = (1 &amp;lt;&amp;lt; n) - 1;
	for(int s = 1;s &amp;lt;= S;s++) sum[s] = sum[s ^ (s &amp;amp; -s)] + sum[s &amp;amp; -s];
	g[0] = 1;
	for(int i = 0;i &amp;lt; n;i++) f[1 &amp;lt;&amp;lt; i] = 1;
	for(int s = 0;s &amp;lt;= S;s++) for(int i = 0;i &amp;lt; n;i++){
		if(s &amp;gt;&amp;gt; i &amp;amp; 1) continue;
		if(sum[s] &amp;gt;= 0) (f[s | (1 &amp;lt;&amp;lt; i)] += f[s]) %= MOD;
		if(sum[s | (1 &amp;lt;&amp;lt; i)] &amp;lt; 0) (g[s | (1 &amp;lt;&amp;lt; i)] += g[s]) %= MOD;
	}
	int ans = 0;
	for(int s = 0;s &amp;lt;= S;s++) (ans += ((sum[s] % MOD + MOD) % MOD) * f[s] % MOD * g[S ^ s] % MOD) %= MOD;
	printf(&quot;%d\n&quot; , ans);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CF449D &amp;amp; P6442&lt;/h3&gt;
&lt;p&gt;P6442：要求或起来为全集的方案数，不妨取反，于是变成求与起来为空集的方案数。&lt;/p&gt;
&lt;p&gt;先求出$ f_s $表示有多少个数有$ s $。&lt;/p&gt;
&lt;p&gt;然后$ g_s $表示与起来为$ s $超集的方案数，显然为$ 2^{f_s}-1 $。&lt;/p&gt;
&lt;p&gt;然后差分回去就可以求出与起来为$ 0 $的方案数了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
typedef long long ll;

const int MOD = 1e9 + 7;
int n , a[2000005];
ll f[2000005];

inline ll qpow(ll x , ll y){ ll ret = 1; while(y){ if(y &amp;amp; 1) ret = ret * x % MOD; x = x * x % MOD; y &amp;gt;&amp;gt;= 1; } return ret; }

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;a[i]) , f[a[i]]++;
	const int S = (1 &amp;lt;&amp;lt; 20) - 1;
	for(int i = 0;i &amp;lt; 20;i++) for(int j = 0;j &amp;lt;= S;j++)
		if(!(j &amp;gt;&amp;gt; i &amp;amp; 1)) f[j] += f[j ^ (1 &amp;lt;&amp;lt; i)];
	for(int s = 0;s &amp;lt;= S;s++) f[s] = (qpow(2 , f[s]) - 1 + MOD) % MOD;
	for(int i = 0;i &amp;lt; 20;i++) for(int j = 0;j &amp;lt;= S;j++)
		if(!(j &amp;gt;&amp;gt; i &amp;amp; 1)) (f[j] += MOD - f[j ^ (1 &amp;lt;&amp;lt; i)]) %= MOD;
	printf(&quot;%lld\n&quot; , f[0]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CF1208F&lt;/h3&gt;
&lt;p&gt;比较喵的一道题。&lt;/p&gt;
&lt;p&gt;可以枚举第一个数，考虑最大化，于是贪心从高位取。&lt;/p&gt;
&lt;p&gt;每次判断是否存在两个不同且下标大于 i 的数的与是当前枚举的超集。&lt;/p&gt;
&lt;p&gt;这个可以用高维前缀和预处理。&lt;/p&gt;
&lt;p&gt;$ f_s $表示为$ s $超集的下标最大值与次大值。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

int n , a[1000005];

struct QWQ {
	int a , b; //a &amp;gt; b
	inline QWQ(int _ = 0 , int __ = 0){ a = _; b = __; }
	inline QWQ friend operator + (const QWQ p , const QWQ q){
		if(p.a &amp;lt; q.a) return QWQ(q.a , max(p.a , q.b));
		return QWQ(p.a , max(p.b , q.a));
	}
}f[2097154];

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%d&quot; , &amp;amp;a[i]);
		f[a[i]] = f[a[i]] + QWQ(i , 0);
	}
	const int S = (1 &amp;lt;&amp;lt; 21) - 1;
	for(int i = 0;i &amp;lt; 21;i++) for(int s = 0;s &amp;lt;= S;s++)
		if(!(s &amp;gt;&amp;gt; i &amp;amp; 1)) f[s] = f[s] + f[s ^ (1 &amp;lt;&amp;lt; i)];
	int ans = 0;
	for(int i = 1;i &amp;lt;= n - 2;i++){
		int nw = 0;
		for(int j = 20;j &amp;gt;= 0;j--){
			if(a[i] &amp;gt;&amp;gt; j &amp;amp; 1) continue;
			if(f[nw | (1 &amp;lt;&amp;lt; j)].b &amp;gt; i) nw |= (1 &amp;lt;&amp;lt; j);
		}
		ans = max(ans , (nw | a[i]));
	}
	printf(&quot;%d\n&quot; , ans);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;计数 &amp;amp; 概率&lt;/h2&gt;
&lt;h1&gt;形式&lt;/h1&gt;
&lt;h2&gt;括号 :(&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;看成&lt;code&gt;(..)(..)(..)...&lt;/code&gt;和&lt;code&gt;(...)&lt;/code&gt;dp&lt;/li&gt;
&lt;li&gt;拆第一个成对括号，然后剩下的是同样的形式。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;(&lt;/code&gt;看成 1，&lt;code&gt;)&lt;/code&gt;看成 -1。前缀和非负。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;基环树&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;前置：树形dp&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这是非树，但是有很好的性质的特殊图，他删掉一条边可以变为树，而且有且仅有一个环。&lt;/p&gt;
&lt;p&gt;只要满足一个联通块内恰好有 n 条边，那么这个联通块就是基环树。&lt;/p&gt;
&lt;p&gt;一般有两种 dp 方法：&lt;/p&gt;
&lt;h3&gt;是环&lt;/h3&gt;
&lt;p&gt;由于只有一个环，那么直接将环缩成点，就是树了，最后再在环上特殊处理即可。&lt;/p&gt;
&lt;h3&gt;是边&lt;/h3&gt;
&lt;p&gt;删掉一条边即可变为树，于是先删掉一条反祖边，树形 dp，特殊处理。&lt;/p&gt;
&lt;h3&gt;技巧&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;用并查集找反祖边。&lt;/li&gt;
&lt;li&gt;dfs找环。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;小试&lt;/h3&gt;
&lt;h4&gt;a. P4381 Island&lt;/h4&gt;
&lt;p&gt;可以转换成基环树求直径问题。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;定义：基环树的直径为基环树上最长路径，非两点间最短路径。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先找出环，标记出来，这样就有了若干棵子树，对每棵子树求直径和从根节点出发的最长路径。&lt;/p&gt;
&lt;p&gt;如果把最长路径当做环的点权，那么问题就变成在环上找一条路径，路径权值为经过点权和与路径和，不能重复走点，求最长路径。&lt;/p&gt;
&lt;p&gt;显然，断环成链，把节点复制一份，把边权算到右边的点权上，这样就变成最大区间和了，单调队列即可做。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 这是一张图片，ocr 内容为：3 2 6 83 10 2 01 8 5 洛谷@_LEAVING --&amp;gt;
&lt;img src=&quot;https://cdn.nlark.com/yuque/0/2025/png/34441004/1756265131778-c823f149-8874-4ae8-9734-7c1f13a57737.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;（偷了张博客的图。。）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
typedef long long ll;

struct ZBJ { int x , w , id; };
vector &amp;lt;ZBJ&amp;gt; g[1000005];

int n;

int _f[1000005]; pair &amp;lt;int , int&amp;gt; ni[1000005]; int ni_cnt;
int find(int x){ return _f[x] == x? x : _f[x] = find(_f[x]); }

int huan[1000005] , onhuan[1000005] , tot;
ll a[2000005] , b[2000005];
bool find_huan(int x , int lt){
	if(huan[x] == 2){ return 1; }
	huan[x] = 2;
	for(ZBJ nxt : g[x]) if(nxt.id != lt){
		if(find_huan(nxt.x , nxt.id)){
			huan[x] = 1; onhuan[++tot] = x;
			b[tot] = nxt.w;
			return 1;
		}
	}
	huan[x] = -1;
	return 0;
}

ll ansd;
pair &amp;lt;ll , ll&amp;gt; dp[1000005]; //直径
void dfs(int x , int lt){
	dp[x] = {0 , 0};
	for(ZBJ nxt : g[x]) if(nxt.id != lt &amp;amp;&amp;amp; huan[nxt.x] != 1){
		dfs(nxt.x , nxt.id);
		const ll t1 = dp[nxt.x].first + nxt.w;
		if(t1 &amp;gt;= dp[x].first)
			dp[x].second = dp[x].first , dp[x].first = t1;
		else if(t1 &amp;gt; dp[x].second)
			dp[x].second = t1;
	}
	ansd = max(ansd , dp[x].first + dp[x].second);
}

pair &amp;lt;ll , int&amp;gt; q[1000005]; int tl , hd;
inline ll solve(int x){
	ansd = 0; tot = 0; hd = 1; tl = 0;
	find_huan(ni[x].first , 0);
	for(int i = 1;i &amp;lt;= tot;i++){
		dfs(onhuan[i] , 0);
		a[i + tot] = a[i] = dp[onhuan[i]].first;
		// if(n == 15) printf(&quot;%d %d\n&quot; , onhuan[i] , a[i]);
	}
	b[tot + 1] = b[1];
	b[1] = 0;
	for(int i = 2;i &amp;lt; tot;i++) b[i + tot] = b[i];
	int m = tot + tot - 1;
	// for(int i = 1;i &amp;lt;= m;i++) printf(&quot;%d:%d %d\n&quot; , i , a[i] , b[i]);
	// puts(&quot;&quot;);
	for(int i = 1;i &amp;lt;= m;i++) b[i] += b[i - 1];

	ll ret = ansd;
	for(int i = 2;i &amp;lt;= tot;i++){
		while(tl &amp;gt;= hd &amp;amp;&amp;amp; q[tl].first &amp;lt;= b[i] + a[i]) tl--;
		q[++tl] = {b[i] + a[i] , i};
	}
	for(int i = 1;i &amp;lt;= tot;i++){
		while(tl &amp;gt;= hd &amp;amp;&amp;amp; q[hd].second &amp;lt;= i) hd++;
		// printf(&quot;%d\n&quot; , q[hd].first);
		ret = max(ret , a[i] - b[i] + q[hd].first);
		while(tl &amp;gt;= hd &amp;amp;&amp;amp; q[tl].first &amp;lt;= b[i + tot] + a[i + tot]) tl--;
		q[++tl] = {b[i + tot] + a[i + tot] , i + tot};
	}
	for(int i = 0;i &amp;lt;= m + 1;i++) a[i] = b[i] = 0;
	// printf(&quot;ret%d\n&quot; , ret);
	return ret;
}

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++) _f[i] = i;
	for(int i = 1 , v , w;i &amp;lt;= n;i++){
		scanf(&quot;%d%d&quot; , &amp;amp;v , &amp;amp;w);
		g[i].push_back((ZBJ){v , w , i});
		g[v].push_back((ZBJ){i , w , i});
		if(find(i) == find(v)){ ni[++ni_cnt] = {i , v}; continue; }
		_f[find(i)] = find(v);
	}
	ll ans = 0;
	for(int i = 1;i &amp;lt;= ni_cnt;i++) ans += solve(i);
	printf(&quot;%lld\n&quot; , ans);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;b. P2607 骑士&lt;/h4&gt;
&lt;p&gt;比较简单，因为不保证联通，于是是基环森林，每个联通快都是 n 条边，于是是基环树。&lt;/p&gt;
&lt;p&gt;又因为相互没有影响，于是分开考虑。发现当成树的子问题是最大独立集，简单树形 dp 可做，再考虑反祖边，这两点不能同时选，那么强制某个点不选再取最大即可。&lt;/p&gt;
&lt;h2&gt;排列类&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/xt2szowt&quot;&gt;https://www.luogu.com.cn/article/xt2szowt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;直接按照下标转移的暂时不说。&lt;/p&gt;
&lt;h3&gt;插入法&lt;/h3&gt;
&lt;p&gt;我们按照值从小到大插入，即$ f_i $表示插入了小于等于$ i $的所有数的答案。&lt;/p&gt;
&lt;h4&gt;AT_dp_t Permutation&lt;/h4&gt;
&lt;p&gt;$ f_{i,j} $表示前$ i $个，前一个插的排名为$ j $，转移不难。&lt;/p&gt;
&lt;h3&gt;连续段dp&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/chroneZ/p/17938137&quot;&gt;https://www.cnblogs.com/chroneZ/p/17938137&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/stinger/p/16471744.html&quot;&gt;https://www.cnblogs.com/stinger/p/16471744.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/best-brain/p/18006547&quot;&gt;https://www.cnblogs.com/best-brain/p/18006547&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;有点像扫描线，我们以加入顺序为横轴，位置为纵轴画如上图，然后按照大小顺序从下往上扫（上往下，下往上都可）。&lt;/p&gt;
&lt;p&gt;我们把连在一起的称为一个连续段，连续段 dp 是通过连续段的数量来进行 dp。&lt;/p&gt;
&lt;p&gt;有以下三种情况。&lt;/p&gt;
&lt;p&gt;&amp;lt;!-- 这是一张图片，ocr 内容为：HALLANLLYLLA ]加强病 123456 --&amp;gt;
&lt;img src=&quot;https://cdn.nlark.com/yuque/0/2025/png/34441004/1761825506122-594bedd7-1778-4914-bfbc-d0657b94dc98.png&quot; alt=&quot;延伸(2-&amp;gt;2)&quot; /&gt;&amp;lt;!-- 这是一张图片，ocr 内容为：HYLANLLYLLY - LA ]加强病 123456 --&amp;gt;
&lt;img src=&quot;https://cdn.nlark.com/yuque/0/2025/png/34441004/1761825855681-b154bfce-e338-40ef-8c0d-2fb8eb39b2f6.png&quot; alt=&quot;合并&quot; /&gt;&amp;lt;!-- 这是一张图片，ocr 内容为：HALLALLLLLYLA ]加强病 123456 --&amp;gt;
&lt;img src=&quot;https://cdn.nlark.com/yuque/0/2025/png/34441004/1761826162195-f556707b-142e-43cb-be15-3a53112d631c.png&quot; alt=&quot;新建(2-&amp;gt;3)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;好像不对。。。&lt;/p&gt;
&lt;h4&gt;&amp;lt;font style=&quot;color:#DF2A3F;&quot;&amp;gt;P5999 [CEOI 2016] kangaroo&amp;lt;/font&amp;gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;求波浪型排列（其差分正负交错，没有连续的正或负），满足$ p_1=s,p_n=t $的方案数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;显然可以从小往大插，设$ f_{i,j} $表示插入了前$ i $个数，形成了$ j $个段的方案数。&lt;/p&gt;
&lt;p&gt;我们枚举$ i(i\not = s,i \not = t) $。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新建段：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于$ f_{i-1,j-1} $，它有$ j $个空位，当我们放入$ i $时，显然比之前放的都大，这里没啥限制，都是合法的。&lt;/p&gt;
&lt;p&gt;唯一的限制是$ p_1=s,p_n=t $，所以当$ i+1&amp;gt;s $时，$ p_1 $被放了，空位减，尾同理。&lt;/p&gt;
&lt;p&gt;所以$ (j-[i&amp;gt;s]-[i&amp;gt;t])f_{i-1,j-1} \to f_{i,j} $。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;段添加：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们不能允许这种操作，因为如果允许了，因为只能往块的头尾加，这样一定不满足波浪型限制，不必转移。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;段合并：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无论放哪，两侧相邻的都比$ i $小，合成的新的块仍满足此性质。&lt;/p&gt;
&lt;p&gt;$ jf_{i-1,j+1} \to f_{i,j} $。&lt;/p&gt;
&lt;p&gt;答案即为$ f_{n,1} $。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;

const int MOD = 1e9 + 7;
int n , s , t;
int f[2005][2005];

int main(void){
	scanf(&quot;%d%d%d&quot; , &amp;amp;n , &amp;amp;s , &amp;amp;t);
	f[0][0] = 1;
	for(int i = 1;i &amp;lt;= n;i++) for(int j = 1;j &amp;lt;= i;j++){
		if(i == s || i == t){
			f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % MOD;
			continue;
		}
		f[i][j] = (1LL * j * f[i - 1][j + 1] % MOD + 1LL * (j - (i &amp;gt; s) - (i &amp;gt; t)) * f[i - 1][j - 1] % MOD) % MOD;
	}
	printf(&quot;%d\n&quot; , f[n][1]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;CF1515E&lt;/h4&gt;
&lt;p&gt;设$ f_{i,j} $加入了前$ i $个点，一共有$ j $个连续段。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新建：$ f_{i,j}\times(j+1)\longrightarrow f_{i+1,j+1} $。
&lt;ul&gt;
&lt;li&gt;系数：有$ (j+1) $个空位。&lt;/li&gt;
&lt;li&gt;为什么能加：不知道&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;优化&lt;/h1&gt;
&lt;h2&gt;单调队列&lt;/h2&gt;
&lt;h2&gt;决策单调性&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/alex-wei/p/DP_optimization_method_II.html&quot;&gt;https://www.cnblogs.com/alex-wei/p/DP_optimization_method_II.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/birchtree/p/12937975.html&quot;&gt;https://www.cnblogs.com/birchtree/p/12937975.html&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;四边形不等式&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;定义1：若对于$ \forall a\le b \le c \le d $，满足$ w(a,d)+w(b,c)\ge w(a,c)+w(b,d) $。则称$ w $满足四边形不等式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面的推论比较好用。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;推论1.1：对于$ \forall a &amp;lt; b $，满足$ w(a,b+1)+w(a+1,b)\ge w(a,b)+w(a+1,b+1) $则$ w $满足四边形不等式。&lt;/p&gt;
&lt;p&gt;证明：设$ a&amp;lt;c,a+1&amp;lt;c $可得两式，相加可证$ a&amp;lt;b&amp;lt;c,w(a,c+1)+w(b,c)\ge w(a,c)+w(b , c+1) $，同样可证出&lt;/p&gt;
&lt;p&gt;$ w(a,d)+w(b,c)\ge w(a,c)+w(b,d) $，所以满足四边形不等式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论1.2：若$ w $满足四边形不等式，那么$ w $&amp;lt;font style=&quot;color:rgb(0, 0, 0);&quot;&amp;gt;满足凸完全单调性，即&amp;lt;/font&amp;gt;$ w $&amp;lt;font style=&quot;color:rgb(0, 0, 0);&quot;&amp;gt;是凸函数。&amp;lt;/font&amp;gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;从四边形不等式到决策单调性&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;定义2：对于$ f_i=\min{f_j+w(j,i)| 0 \le j &amp;lt; i} $的状态转移方程，若$ j=p_i $时可让$ f_i $取得最小值，则$ p_i $为$ f_i $的最优决策点。若$ p_i $单调不降，那么称$ f $具有决策单调性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定理2.1：若$ w $满足四边形不等式，那么$ f $具有决策单调性。&lt;/p&gt;
&lt;p&gt;证明：&lt;/p&gt;
&lt;p&gt;$ \forall i \in [1,n],j\in[0,p_i) $，根据$ p_i $的定义得：$ f_{p_i}+w(p_i,i)\le f_j+w(j,i)\tag 1 $&lt;/p&gt;
&lt;p&gt;$ \forall i&apos;\in(i,n] $，此时$ j&amp;lt;p_i&amp;lt;i&amp;lt;i&apos; $，所以$ w(j,i&apos;)+w(p_i,i)\ge w(j,i)+w(p_i,i&apos;) $&lt;/p&gt;
&lt;p&gt;移项得：$ w(p_i,i&apos;)-w(p_i,i)\le w(j,i&apos;)-w(j,i) \tag 2 $&lt;/p&gt;
&lt;p&gt;$ (1)+(2) $得：$ f_{p_i}+w(p_i,i&apos;)\le f_j+w(j,i&apos;) $&lt;/p&gt;
&lt;p&gt;所以$ j&amp;lt;p_i $的一定没有决策点$ p_i $优，于是$ f_{i&apos;} $的最优决策点$ p_{i&apos;}\ge p_i $，所以$ f $具有决策单调性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;大胆假设&lt;/h3&gt;
&lt;p&gt;一般题目可以通过枚举（瞎猜）来验证四边形不等式，无需严格证明。&lt;/p&gt;
&lt;p&gt;然后你就拥有了一个很强的性质：决策单调性。于是你可以使用以下几种方式优化成$ O(n\log n) $&lt;/p&gt;
&lt;h4&gt;以分治&lt;/h4&gt;
&lt;p&gt;适用范围：$ f $转移不与当前层的$ f $有关。&lt;/p&gt;
&lt;p&gt;比较简单的想法，由于决策单调性，所以对于$ f_i $可能的决策点是一个区间。&lt;/p&gt;
&lt;p&gt;可以利用分治先求出$ f_{mid} $再求出左右区间的决策点范围。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void solve(int l , int r , int ql , int qr){
	int mid = (l + r) &amp;gt;&amp;gt; 1 , k = ql;
	for(int i = ql , _ = min(mid - 1 , qr);i &amp;lt;= _;i++) if(v(i , mid) &amp;gt; p[mid])
		p[mid] = v(i , mid) , k = i;
	if(l &amp;lt; mid) solve(p , l , mid - 1 , ql , k);
	if(mid &amp;lt; r) solve(p , mid + 1 , r , k , qr);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;以二分队列&lt;/h4&gt;
&lt;p&gt;适用范围：决策点单调不降。&lt;/p&gt;
&lt;p&gt;考虑每个点可能作为最优决策点的范围，容易证明一定成区间。&lt;/p&gt;
&lt;p&gt;我们可以用$ (x,l,r) $表示决策点$ x $可能作为$ [l,r] $的$ f $的最优决策点，放进队列里。&lt;/p&gt;
&lt;p&gt;然后分三步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;无法成为$ f_i $的最优决策点的出队列。&lt;/li&gt;
&lt;li&gt;更新$ f_i $。&lt;/li&gt;
&lt;li&gt;出队。
&lt;ol&gt;
&lt;li&gt;加入队尾严格劣于$ i $，那么这个决策点一定不优。这里可以通过对$ l $的贡献大小判断。&lt;/li&gt;
&lt;li&gt;空队列，直接加$ (i,i+1,n) $。&lt;/li&gt;
&lt;li&gt;如果队尾部分优于$ i $，那么需要修改队尾的区间。由于区间连续，则一定存在一点满足左边队尾优，右边$ i $优，那么可以二分找出来。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;struct SB{ int x,  l , r; };
deque &amp;lt;SB&amp;gt; q;
q.push_back((SB){0 , 1 , n});
for(int i = 1;i &amp;lt;= n;i++){
    while(!q.empty() &amp;amp;&amp;amp; q.front().r &amp;lt; i) q.pop_front();
    q.front().l = i;
    f[i] = v(p[i] = q.front().x , i);
    while(!q.empty() &amp;amp;&amp;amp; v(i , q.back().l) &amp;lt;= v(q.back().x , q.back().l)) q.pop_back();
    if(q.empty()){ q.push_back((SB){i , i + 1 , n}); continue; }
    int l = q.back().l , r = q.back().r + 1 , ret = r;
    while(l &amp;lt;= r){
        int mid = (l + r) &amp;gt;&amp;gt; 1;
        if(v(i , mid) &amp;lt;= v(q.back().x , mid)){ ret = mid; r = mid - 1; }
        else l = mid + 1;
    }
    if(ret &amp;lt;= n){
        q.back().r = ret - 1;
        q.push_back((SB){i , ret , n});
    }
} 
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;以二分栈&lt;/h4&gt;
&lt;h3&gt;斜率优化&lt;/h3&gt;
&lt;p&gt;&amp;lt;font style=&quot;color:rgb(35, 38, 59);background-color:rgba(255, 255, 255, 0.9);&quot;&amp;gt;一些只和&amp;lt;/font&amp;gt;$ i,j $&amp;lt;font style=&quot;color:rgb(35, 38, 59);background-color:rgba(255, 255, 255, 0.9);&quot;&amp;gt;有关的项和一个和&amp;lt;/font&amp;gt;$ i,j $&amp;lt;font style=&quot;color:rgb(35, 38, 59);background-color:rgba(255, 255, 255, 0.9);&quot;&amp;gt;都有关的项的和，一般可以使用斜率优化。&amp;lt;/font&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;font style=&quot;color:rgb(35, 38, 59);background-color:rgba(255, 255, 255, 0.9);&quot;&amp;gt;例如：&amp;lt;/font&amp;gt;&lt;/p&gt;
&lt;p&gt;$ f_i=\max{f_j+a_i+a_j+b_ib_j} $&lt;/p&gt;
&lt;p&gt;假如$ i $一定，可以看成关于$ j $的函数。&lt;/p&gt;
&lt;p&gt;$ f_i-a_i-b_ib_j=f_j+a_j $&lt;/p&gt;
&lt;p&gt;观察$ b+kx=y $，得：&lt;/p&gt;
&lt;p&gt;$ b=f_i-a_i,k=-b_i,x=b_j,y=f_j+a_j $&lt;/p&gt;
&lt;p&gt;现在已知所有的$ (x,y) $，要求出最大的$ f_i=b+a_i $，因为$ a_i,k $是常数，所以相当于找最大的$ b $使得直线能经过一个点$ (x,y) $。&lt;/p&gt;
&lt;h3&gt;尝天下鲜&lt;/h3&gt;
&lt;h4&gt;&amp;lt;font style=&quot;color:rgba(0, 0, 0, 0.75);&quot;&amp;gt;P1912 小G诗人&amp;lt;/font&amp;gt;&lt;/h4&gt;
&lt;p&gt;设$ s_i=i+\sum |s_j| $&lt;/p&gt;
&lt;p&gt;所以$ f_i=\min{f_j+|s_i-s_j-1-L|^P} $&lt;/p&gt;
&lt;p&gt;猜测满足四边形不等式，于是具有决策单调性。&lt;/p&gt;
&lt;p&gt;所以直接用二分队列优化就行了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
typedef long double ll; 

const ll MAX = 1000000000000000007;
int T , n , L , P;

char str[3200005]; int  _;
struct ZBj{
	int st , le;
	inline void read(){
		st = _;
		scanf(&quot;%s&quot; , str + st);
		le = strlen(str + st);
//		printf(&quot;%d %d %s\n&quot; , _ , le , str + st);
		_  += le + 2;
	}
}a[100005]; int s[100005];
ll f[100005]; int p[100005];

inline ll mul(ll x , ll y){ return x * y; }
inline ll add(ll x , ll y){ return x + y; }

inline ll qpow(ll x , int y){
	if(x == 0) return 0;
	ll ret = 1;
	while(y){
		if(y &amp;amp; 1) ret = mul(ret , x);
		x = mul(x , x); y &amp;gt;&amp;gt;= 1;
	}
	return ret;
}

inline ll v(int j , int i){ return add(f[j] , qpow(abs(s[i] - s[j] - 1 - L) , P)); }

void print(int x){
	if(x &amp;lt;= 0) return ;
	print(p[x]);
	for(int i = p[x] + 1;i &amp;lt;= x;i++) printf(&quot;%s%c&quot; , str + a[i].st , i == x? &apos;\n&apos; : &apos; &apos;);
}

struct SB{ int x,  l , r; };
deque &amp;lt;SB&amp;gt; q;
inline void solve(){
	_ = 0;
	scanf(&quot;%d%d%d&quot; , &amp;amp;n , &amp;amp;L , &amp;amp;P);
	for(int i = 1;i &amp;lt;= n;i++) a[i].read();
	for(int i = 1;i &amp;lt;= n;i++) s[i] = s[i - 1] + a[i].le + 1;
	f[0] = 0;
	q.clear();
	q.push_back((SB){0 , 1 , n});
	for(int i = 1;i &amp;lt;= n;i++){
		while(!q.empty() &amp;amp;&amp;amp; q.front().r &amp;lt; i) q.pop_front();
		q.front().l = i;
		f[i] = v(p[i] = q.front().x , i);
		while(!q.empty() &amp;amp;&amp;amp; v(i , q.back().l) &amp;lt;= v(q.back().x , q.back().l)) q.pop_back();
		if(q.empty()){ q.push_back((SB){i , i + 1 , n}); continue; }
		int l = q.back().l , r = q.back().r + 1 , ret = r;
		while(l &amp;lt;= r){
			int mid = (l + r) &amp;gt;&amp;gt; 1;
//			printf(&quot;%d %d %d\n&quot; , mid , q.back().x , i);
			if(v(i , mid) &amp;lt;= v(q.back().x , mid)){ ret = mid; r = mid - 1; }
			else l = mid + 1;
		}
		if(ret &amp;lt;= n){
			q.back().r = ret - 1;
			q.push_back((SB){i , ret , n});
		}
	} 
	if(f[n] &amp;gt; 1000000000000000000) puts(&quot;Too hard to arrange&quot;);
	else{
		printf(&quot;%.0LF\n&quot; , f[n]);
		print(n);
	}
	puts(&quot;--------------------&quot;);
}

int main(void){
//	freopen(&quot;awa.in&quot; , &quot;r&quot; , stdin);
	int T; scanf(&quot;%d&quot; , &amp;amp;T);
	while(T--) solve();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;&amp;lt;font style=&quot;color:rgba(0, 0, 0, 0.75);&quot;&amp;gt;P5503 灯塔&amp;lt;/font&amp;gt;&lt;/h4&gt;
&lt;p&gt;显然可以翻转序列做两遍。&lt;/p&gt;
&lt;p&gt;$ p_i=\max{h_j+\sqrt{i-j}-h_i} $&lt;/p&gt;
&lt;p&gt;可以证明有决策单调性，用分治优化。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cmath&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

int n , h[500005];
double p1[500005] , p2[500005];

void solve(double p[500005] , int l , int r , int ql , int qr){
	int mid = (l + r) &amp;gt;&amp;gt; 1 , k = ql;
	for(int i = ql , _ = min(mid - 1 , qr);i &amp;lt;= _;i++)
		if(h[i] + __builtin_sqrt(mid - i) - h[mid] &amp;gt; p[mid])
			p[mid] = h[i] + __builtin_sqrt(mid - i) - h[mid] , k = i;
	if(l &amp;lt; mid) solve(p , l , mid - 1 , ql , k);
	if(mid &amp;lt; r) solve(p , mid + 1 , r , k , qr);
	
}

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;h[i]);
	//p = max(h[j]+sqrt(i-j))-h[i]
	solve(p1 , 1 , n , 1 , n);
	reverse(h + 1 , h + 1 + n);
	solve(p2 , 1 , n , 1 , n);
	for(int i = 1;i &amp;lt;= n;i++) printf(&quot;%.0lf\n&quot; , ceil(max(p1[i] , p2[n - i + 1])));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;slope trick&lt;/h2&gt;
&lt;h2&gt;线段树&lt;/h2&gt;
&lt;h2&gt;凸优化&lt;/h2&gt;
&lt;h3&gt;wqs 二分&lt;/h3&gt;
&lt;p&gt;WQS 二分通常用于解决这样一类优化问题：它们带有数量限制，直接求解代价较高；但一旦去除这一限制，问题本身就变得容易得多。&lt;/p&gt;
&lt;p&gt;并且要求为凸函数。&lt;/p&gt;
&lt;p&gt;一般的，可以二分选择的代价惩罚，然后根据找到一个代价，使得刚好选到要求的个数。&lt;/p&gt;
&lt;h4&gt;邮局加强版加强版&lt;/h4&gt;
&lt;p&gt;二分放邮局的代价，用四边形不等式优化$ O(n\log n) $算出最优解，然后调整即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
typedef long long ll;

int n , m , a[500005]; ll sum[500005];

inline ll w(int l , int r){
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	return 1LL * (mid - l) * a[mid] - (sum[mid - 1] - sum[l - 1]) + (sum[r] - sum[mid]) - 1LL * (r - mid) * a[mid];
}

struct ZBJ { int x , l , r; };
deque &amp;lt;ZBJ&amp;gt; q;

pair &amp;lt;ll , int&amp;gt; f[500005];

inline ll v(int x , int y){ //x -&amp;gt; y
	return f[x].first + w(x + 1 , y);
}

inline ll solve(ll mid){
	// memset(f , 0x3f , sizeof(f));
	while(!q.empty()) q.pop_front();
	f[0] = {0 , 0};
	q.push_back((ZBJ){0 , 1 , n});
	for(int i = 1;i &amp;lt;= n;i++){
		while(!q.empty() &amp;amp;&amp;amp; q.front().r &amp;lt; i) q.pop_front();
		q.front().l = i;
		f[i] = {v(q.front().x , i) + mid , f[q.front().x].second + 1};
		while(!q.empty() &amp;amp;&amp;amp; v(i , q.back().l) &amp;lt;= v(q.back().x , q.back().l))
			q.pop_back();
		if(q.empty()){ q.push_back((ZBJ){i , i + 1 , n}); continue; }
		int l = q.back().l , r = q.back().r + 1 , ret = r;
		while(l &amp;lt;= r){
			int mi = (l + r) &amp;gt;&amp;gt; 1;
			if(v(i , mi) &amp;lt;= v(q.back().x , mi)){
				ret = mi;
				r = mi - 1;
			}
			else l = mi + 1;
		}
		if(ret &amp;lt;= n){
			q.back().r = ret - 1;
			q.push_back((ZBJ){i , ret , n});
		}
	}
	return f[n].second;
}

int main(void){
	scanf(&quot;%d%d&quot; , &amp;amp;n , &amp;amp;m);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;a[i]);
	sort(a + 1 , a + 1 + n);
	for(int i = 1;i &amp;lt;= n;i++) sum[i] = sum[i - 1] + a[i];
	ll l = 0 , r = 1e12 , ret;
	while(l &amp;lt;= r){
		ll mid = (l + r) &amp;gt;&amp;gt; 1;
		if(solve(mid) &amp;gt;= m){
			ret = mid;
			l = mid + 1;
		}
		else r = mid - 1;
	}
	solve(ret);
	printf(&quot;%lld\n&quot; , f[n].first - ret * m);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;P5896 [IOI 2016] aliens&lt;/h4&gt;
&lt;p&gt;大约可以看成线段覆盖问题。&lt;/p&gt;
&lt;p&gt;首先按照线段$ l $排序，将完全被其他线段包含的去掉（显然对答案没有贡献）。&lt;/p&gt;
&lt;p&gt;画图可知，设$ f_i $位覆盖前$ i $个线段的最小代价。&lt;/p&gt;
&lt;p&gt;于是$ f_i=\min { f_j+(r_i - l_{j+1}+1)^2-\max{r_j-l_{j+1}+1}^2} $。&lt;/p&gt;
&lt;p&gt;用 wqs 二分即可做到 41 分。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
typedef long long ll;

inline ll sqr(int x){ return 1LL * x * x; }

int n , m , k;

struct Line {
	int l , r;
	inline bool operator &amp;lt; (const Line b){ if(l == b.l) return r &amp;gt; b.r; return l &amp;lt; b.l; }
}qwq[1000005]; ll g[1000005];

pair &amp;lt;ll , int&amp;gt; f[1000005];
inline int solve(ll mid){
	memset(f , 0x3f , sizeof(f));
	f[0] = {0 , 0};
	for(int i = 1;i &amp;lt;= n;i++)
		for(int j = 0;j &amp;lt; i;j++)
			f[i] = min(f[i] , {f[j].first - g[j] + sqr(qwq[i].r - qwq[j + 1].l + 1) + mid , f[j].second + 1});
	return f[n].second;
}

int main(void){
	scanf(&quot;%d%d%d&quot; , &amp;amp;n , &amp;amp;m , &amp;amp;k);
	if(n &amp;gt;= 50000){ puts(&quot;NO&quot;); return 0; }
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%d%d&quot; , &amp;amp;qwq[i].l , &amp;amp;qwq[i].r);
		qwq[i].l++; qwq[i].r++;
		if(qwq[i].l &amp;gt; qwq[i].r) swap(qwq[i].l , qwq[i].r);
	}
	sort(qwq + 1 , qwq + 1 + n);
	int chm_qwq = 0;
	for(int i = 1 , r = -1;i &amp;lt;= n;i++)
		if(qwq[i].r &amp;gt; r){ r = qwq[i].r; qwq[++chm_qwq] = qwq[i]; }
	n = chm_qwq;
	for(int i = 1;i &amp;lt; n;i++) g[i] = sqr(max(qwq[i].r - qwq[i + 1].l + 1 , 0));
	ll l = 0 , r = 1e12 , ret = -114514;
	while(l &amp;lt;= r){
		ll mid = (l + r) &amp;gt;&amp;gt; 1LL;
		if(solve(mid) &amp;lt;= k){
			ret = mid;
			r = mid - 1;
		}
		else l = mid + 1;
	}
	solve(ret);
	printf(&quot;%lld\n&quot; , f[n].first - ret * k);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后再对$ f $斜率优化即可 AC&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
typedef long long ll;

inline ll sqr(int x){ return 1LL * x * x; }

int n , m , k;

struct Line {
	int l , r;
	inline bool operator &amp;lt; (const Line b){ if(l == b.l) return r &amp;gt; b.r; return l &amp;lt; b.l; }
}qwq[1000005]; ll g[1000005];

int q[1000005] , hd , tl;
pair &amp;lt;ll , int&amp;gt; f[1000005];

inline ll Y(int x){ return f[x].first - g[x] + sqr(qwq[x + 1].l); }
inline ll X(int x){ return qwq[x + 1].l; }
inline long double count(int x , int y){ return (long double)(Y(x) - Y(y)) / (X(x) - X(y)); }

inline int solve(ll mid){
	q[hd = tl = 1] = 0;
	for(int i = 1;i &amp;lt;= n;i++){
		while(tl &amp;gt; hd &amp;amp;&amp;amp; count(q[hd] , q[hd + 1]) &amp;lt; 2 * qwq[i].r) hd++;
		const int j = q[hd];
		f[i] = {f[j].first - g[j] + sqr(qwq[i].r - qwq[j + 1].l) + mid , f[j].second + 1};
		while(tl &amp;gt; hd &amp;amp;&amp;amp; count(q[tl - 1] , q[tl]) &amp;gt; count(q[tl] , i)) tl--;
		q[++tl] = i;
	}
	// for(int i = 1;i &amp;lt;= n;i++)
	// 	for(int j = 0;j &amp;lt; i;j++)
	// 		f[i] = min(f[i] , {f[j].first - g[j] + sqr(qwq[i].r - qwq[j + 1].l + 1) + mid , f[j].second + 1});
	return f[n].second;
}

int main(void){
	scanf(&quot;%d%d%d&quot; , &amp;amp;n , &amp;amp;m , &amp;amp;k);
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%d%d&quot; , &amp;amp;qwq[i].l , &amp;amp;qwq[i].r);
		if(qwq[i].l &amp;gt; qwq[i].r) swap(qwq[i].l , qwq[i].r);
	}
	sort(qwq + 1 , qwq + 1 + n);
	int chm_qwq = 0;
	for(int i = 1 , r = -1;i &amp;lt;= n;i++)
		if(qwq[i].r &amp;gt; r){ r = qwq[i].r; qwq[++chm_qwq] = qwq[i]; }
	n = chm_qwq;
	for(int i = 1;i &amp;lt; n;i++) g[i] = sqr(max(qwq[i].r - qwq[i + 1].l + 1 , 0));
	for(int i = 1;i &amp;lt;= n;i++) qwq[i].r++;
	ll l = 0 , r = 1e12 , ret = -114514;
	while(l &amp;lt;= r){
		ll mid = (l + r) &amp;gt;&amp;gt; 1LL;
		if(solve(mid) &amp;lt;= k){
			ret = mid;
			r = mid - 1;
		}
		else l = mid + 1;
	}
	solve(ret);
	// printf(&quot;qwq%d %d\n&quot; , ret , solve(ret));
	printf(&quot;%lld\n&quot; , f[n].first - ret * k);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;矩阵&lt;/h2&gt;
&lt;p&gt;技巧：边权小时可以拆点，变成边权为 1。&lt;/p&gt;
&lt;h3&gt;P6569&lt;/h3&gt;
&lt;p&gt;模板，主要是满不满足结合律不好证。&lt;/p&gt;
&lt;p&gt;我也不会证明。。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
typedef long long ll;

int n , m , q;

int N;
struct ZBJ {
	ll a[102][102];
	
	inline void clear(){ for(int i = 1;i &amp;lt;= N;i++) for(int j = 1;j &amp;lt;= N;j++) a[i][j] = 0; }
	
	inline friend ZBJ operator * (const ZBJ x , const ZBJ y) {
		ZBJ ret; ret.clear();
		for(int i = 1;i &amp;lt;= N;i++) for(int j = 1;j &amp;lt;= N;j++)
			for(int k = 1;k &amp;lt;= N;k++)
				ret.a[i][j] ^= x.a[i][k] * y.a[k][j];
		return ret;
	}
}A[35];

ll f[105] , tmp[105];

inline void mul(ll k){
	for(int _ = 0;_ &amp;lt; 32;_++) if(k &amp;gt;&amp;gt; _ &amp;amp; 1){
		for(int i = 1;i &amp;lt;= N;i++) tmp[i] = f[i];
		for(int i = 1;i &amp;lt;= N;i++) f[i] = 0;
		for(int j = 1;j &amp;lt;= N;j++) for(int k = 1;k &amp;lt;= N;k++)
			f[j] ^= tmp[k] * A[_].a[k][j];
//			printf(&quot;%d %d %d %d %d\n&quot; , j , k , f[j] , tmp[j] , A[_].a[k][j]);
	}
}

pair &amp;lt;ll , int&amp;gt; qqq[105]; ll ans[105];

int main(void){
	scanf(&quot;%d%d%d&quot; , &amp;amp;n , &amp;amp;m , &amp;amp;q); N = n;
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%lld&quot; , &amp;amp;f[i]);
	for(int i = 0;i &amp;lt; 32;i++) A[i].clear();
	while(m--){
		int u , v; scanf(&quot;%d%d&quot; , &amp;amp;u , &amp;amp;v);
		A[0].a[u][v] = A[0].a[v][u] = 1;
	}
	for(int i = 1;i &amp;lt;= q;i++) scanf(&quot;%lld&quot; , &amp;amp;qqq[i].first) , qqq[i].second = i;
	sort(qqq + 1 , qqq + 1 + q);
	for(int i = 1;i &amp;lt; 32;i++) A[i] = A[i - 1] * A[i - 1];
	ll lt = 0;
	for(int i = 1;i &amp;lt;= q;i++){
		mul(qqq[i].first - lt); lt = qqq[i].first;
		ans[qqq[i].second] = f[1];
	}
	for(int i = 1;i &amp;lt;= q;i++) printf(&quot;%lld\n&quot; , ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;P6772&lt;/h3&gt;
&lt;p&gt;这题很容易写出 $ f_{v,j}=\max{ f_{i,j-w}+c_v} $，这还不是很符合$ (\max,+) $矩阵。&lt;/p&gt;
&lt;p&gt;发现$ w\le 5 $，很小，拆边边太多了，于是拆点，每个点拆成 5 个，连边就可以连$ (u,w) $和$ (v,1) $就可以了。&lt;/p&gt;
&lt;p&gt;这样没条边的边权都为 1 了，直接放到矩阵上，点数为$ 5n $。&lt;/p&gt;
&lt;p&gt;但是这样无法处理节日，因此可以分段，按照时间排个序，然后按照上题的方法优化，跑完后更新。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;
typedef long long ll;
#define ID(x , k) ((x) + (k - 1) * n) 

const ll inf = 1e16;
int n , m , T , k; ll a[255];

int N;
struct ZBJ {
	ll a[252][252];
	
	inline void clear(){ for(int i = 1;i &amp;lt;= N;i++) for(int j = 1;j &amp;lt;= N;j++) a[i][j] = -inf; } 
	
	inline friend ZBJ operator * (const ZBJ x , const ZBJ y) {
		ZBJ ret; ret.clear();
		for(int i = 1;i &amp;lt;= N;i++) for(int j = 1;j &amp;lt;= N;j++)
			for(int k = 1;k &amp;lt;= N;k++)
				ret.a[i][j] = max(ret.a[i][j] , x.a[i][k] + y.a[k][j]);
		return ret;
	}
}A[31];

ll f[2][252];

inline void mul(int k , int nw , int lt){
	for(int _ = 0;_ &amp;lt; 30;_++) if(k &amp;gt;&amp;gt; _ &amp;amp; 1){
		for(int i = 1;i &amp;lt;= N;i++) f[nw][i] = -inf;
		for(int i = 1;i &amp;lt;= N;i++) for(int j = 1;j &amp;lt;= N;j++)
			f[nw][i] = max(f[nw][i] , f[lt][j] + A[_].a[j][i]);
		for(int i = 1;i &amp;lt;= N;i++) f[lt][i] = f[nw][i];
	}
}

struct SB { int t , x , y; inline bool operator &amp;lt; (const SB &amp;amp;b) { return t &amp;lt; b.t; } }th[205];

int main(void){
	scanf(&quot;%d%d%d%d&quot; , &amp;amp;n , &amp;amp;m , &amp;amp;T , &amp;amp;k);
	N = n * 5;
	for(int i = 0;i &amp;lt; 30;i++) A[i].clear();
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%lld&quot; , &amp;amp;a[i]);
		for(int j = 1;j &amp;lt; 5;j++)  A[0].a[ID(i , j)][ID(i , j + 1)] = 0;
	}
	while(m--){
		int u , v , w; scanf(&quot;%d%d%d&quot; , &amp;amp;u , &amp;amp;v , &amp;amp;w);
		A[0].a[ID(u , w)][v] = max(A[0].a[ID(u , w)][v] , a[v]);
	}
	for(int i = 1;i &amp;lt;= k;i++) scanf(&quot;%d%d%d&quot; , &amp;amp;th[i].t , &amp;amp;th[i].x , &amp;amp;th[i].y);
	sort(th + 1 , th + 1 + k);
	if(th[k].t != T) th[++k] = (SB){T , 0 , 0};
	for(int i = 1;i &amp;lt;= N;i++) f[0][i] = f[1][i] = -inf;
	f[0][1] = a[1];
	for(int i = 1;i &amp;lt; 30;i++) A[i] = A[i - 1] * A[i - 1];
	int lt = 0;
	for(int i = 1;i &amp;lt;= k;i++){
		mul(th[i].t - lt , (i &amp;amp; 1) , (i &amp;amp; 1 ^ 1));
		if(f[th[i].x] &amp;gt;= 0) f[i &amp;amp; 1][th[i].x] += th[i].y;
		lt = th[i].t;
	}
	if(f[k &amp;amp; 1][1] &amp;lt;= 0) puts(&quot;-1&quot;);
	else printf(&quot;%lld\n&quot; , f[k &amp;amp; 1][1]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;T547970&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/problem/T547970&quot;&gt;link&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;突然发现我好久之前做数学题出的题，当时觉得太简单了，现在看来是太典了。&lt;/p&gt;
</content:encoded></item><item><title>数论基础学习</title><link>https://qwq-senlin.cc.cd/post/OI-math/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/OI-math/</guid><description>信息数论散记</description><pubDate>Mon, 20 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;基础&lt;/h1&gt;
&lt;p&gt;更简单的就不说了。&lt;/p&gt;
&lt;h2&gt;a. 逆元&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定义a.1：满足 $ax \equiv 1 \pmod p$ 的 $x$ 称为 $a$ 的逆元&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论a.1.1：当满足 $\gcd(a,p) = 1$ 时，逆元存在。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可用费马小定理或 exgcd 求解。&lt;/p&gt;
&lt;h2&gt;b. 积性函数&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定义b.1：在数论中，若函数 $f(n)$ 满足 $f(1)=1$，且 $f(xy)=f(x)f(y)$ 对任意互质的 $x, y \in\mathbf{N}^*$ 都成立，则 $f(n)$ 为 积性函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定义b.2：在数论中，若函数 $f(n)$ 满足 $f(1)=1$ 且 $f(xy)=f(x)f(y)$ 对任意的 $x, y \in\mathbf{N}^*$ 都成立，则 $f(n)$ 为 完全积性函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;常见积性函数：$\varphi,\mu$。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;完全积性函数：$id(id(n)=n),I(I(n)=1),\epsilon(\epsilon(n)=[n=1])$。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;b.1. 性质&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;性质b.1.1：若 $f(x)$ 为积性函数，那么 $f(x^p),f^p(x)$ 也为积性函数。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性质b.1.2：若 $f(x),g(x)$ 为积性函数，那么 $f(x)g(x),h(x)=\sum_{d|x}f(x)g(\frac{x}{d})$ 也为积性函数。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;c. 迪利克雷卷积&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定义c.1：$(f*g)(x)=\sum_{d|x}f(d)g(\frac{x}{d})$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论c.2：若 $f(x),g(x)$ 为积性函数，那么 $f*g$ 为积性函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论c.2：若 $f(x),g(x)$ 为完全积性函数，那么 $f*g$ 为完全积性函数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论c.3：$f&lt;em&gt;h=g&lt;/em&gt;h \iff f * g$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$f*\epsilon=f$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$\mu * I=\epsilon$（莫比乌斯反演）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$\varphi * I = id$（欧拉反演）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$\mu * id = \varphi$（综上可证）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;道阻且长....&lt;/p&gt;
&lt;h1&gt;1. 费马小定理&amp;amp;欧拉定理&lt;/h1&gt;
&lt;h2&gt;1.1. 费马小定理&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定理1.1.1：当存在整数 $a$ 和质数 $p$ 时，那么：
$a^p \equiv a\pmod p$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定理1.1.2：当整数 $a$ 和质数 $p$ 并且 $\gcd(a,p)=1$ 时，那么：
$a^{p - 1} \equiv 1\pmod p$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论1.1.3：$a^{b} \equiv a^{b \bmod (p-1)}\pmod p$。读者自证不难。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;证明1.1：oi-wiki.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;看下文可以知道，费马小定理是欧拉定理的特殊情况。&lt;/p&gt;
&lt;h2&gt;1.2. 欧拉定理&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定义1.2.1：当 $a, m \in \mathbb{Z}$  ，且  $\operatorname{gcd}(a, m)=1$  时有：$a^{\varphi(m)} \equiv 1\pmod m$ 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;证明1.2.1：https://zhuanlan.zhihu.com/p/452185813&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里 $\varphi(x)$ 是数论中的欧拉函数。$^{*1}$。&lt;/p&gt;
&lt;p&gt;$^{*1}$：详见 4.1。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;推论1.2.2：$a^{b} \equiv a^{b \bmod \varphi(m)}\pmod m$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.2.4 阶&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;定义1.2.4.1：若存在最小非负整数$x$满足 $a^x \equiv 1 \pmod m$，则称 $x$ 为 $a$ 模 $m$ 的阶，记为 $\delta_m(a)$。
根据欧拉定理，显然要满足 $\gcd(a,m)=1$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定理1.2.4.2：$a^x \equiv 1\pmod m$，则$\delta_m(a)|x$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;证明1.2.4.2：设 $x=qd+r$，其中 $0\le r &amp;lt; \delta_m(a)$，由于 $\delta_m(a)$ 最小，所以 $q\ge 1$。所以 $a^r\equiv a^r (a^{\delta_m(a)})^q \equiv a^{q\delta_m(a)+r} \equiv 1 \pmod m$。&lt;/p&gt;
&lt;p&gt;于是$r$只能为$0$，得证。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定理1.2.4.3：$a,a^2,...,a^{\delta_m(a)}$ 模 $m$ 意义下两两不同余。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;证明1.2.4.3：考虑反证，假设存在两个数 $i \neq j$  ，且 $a^{i} \equiv a^{j}(\bmod m)$  ，则有  $a^{|i-j|} \equiv 1(\bmod m)$  ．但是显然的有：$0&amp;lt;|i-j|&amp;lt;\delta_{m}(a)$，这与阶的最小性矛盾，故原命题成立。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;所以当 $a^p\equiv a^q \pmod m$ 时，$p\equiv q \pmod {\delta_m(a)}$。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;定理1.2.4.4：$a,b$ 为整数，那么 $\gcd(\delta_m(a),\delta_m(b))=1$ 的充要条件是 $\delta_m(ab)=\delta_m(a)\delta_m(b)$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;证明1.2.4.4：不会。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;1.2.5 原根&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;定义1.2.5.1：满足$\delta_m(a)=\varphi(m)$的$a$，称 $a$ 为模 $m$ 的原根。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;原根个数：$\varphi(\varphi(m))$。&lt;/p&gt;
&lt;p&gt;原根判定：设 $\varphi(m)$ 的质因数为 $p_1,...p_{s}$，那么 $g$ 是 $m$ 原根的充要条件是：对于任意 $p_i$，满足 $g^{\frac{\varphi(m)}{p_i}}\not\equiv 1 \pmod m$。&lt;/p&gt;
&lt;p&gt;证明：充分性显然。必要性不会&lt;/p&gt;
&lt;p&gt;$m$ 存在原根，当且仅当 $m=2,4$ 或 $m=p^u,2p^u$，其中 $u$ 为大于 $2$ 的质数。
证明不会。&lt;/p&gt;
&lt;h2&gt;1.3. 扩展欧拉定理&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定义1.3.1：当  $a, m \in \mathbb{Z}$  时有：
$$\
a^{b} \equiv\left{\begin{array}{cl}
a^{b} &amp;amp; , b&amp;lt;\varphi(m) \
a^{b \bmod \varphi(m)+\varphi(m)} &amp;amp; , b \ge \varphi(m)
\end{array}\pmod m \right.
$$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;2. 裴蜀定理&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;定义2.1：$p,q$ 非零整数，则对于任意整数 $a,b$ 使得 $\gcd(p,q)|pa+pb$，存在整数 $a,b$ 使得 $pa+pb=\gcd(p,q)$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推广2.1：多个数也成立。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论2.2：若 $p,q$ 互质，则存在整数 $a,b$ 使得 $pa+qb=1$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;证明2.2：设 $pa+qb=m$，其中 $m$ 为可能的最小正整数。即证 $m=1\iff m|p,m|q$。&lt;/p&gt;
&lt;p&gt;假设不成立，则 $p=nm+r(0&amp;lt;r&amp;lt;m)$，可得 $r=p-nm=p-n(pa+qb)=p(1-na)+q(-nb)$。由于 $1-na,-nb$ 为整数，所以 $r$ 为比 $m$ 更小的正整数，与 $m$ 为可能的最小正整数不符，所以假设不成立，$m=1$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;3. 扩展欧几里得算法&lt;/h1&gt;
&lt;p&gt;扩展欧几里得算法常用于求 $ax+by=\gcd(a,b)$ 的可行解。&lt;/p&gt;
&lt;p&gt;以下是算法原理。&lt;/p&gt;
&lt;p&gt;设&lt;/p&gt;
&lt;p&gt;$ax_1+by_1=\gcd(a,b)$&lt;/p&gt;
&lt;p&gt;$bx_2+(a\bmod b)y_2=\gcd(b,a\bmod b)$&lt;/p&gt;
&lt;p&gt;由欧拉定理（$\gcd(a,b)=\gcd(b , a \bmod b)$）可得：
$$
ax_1+by_1=bx_2+(a\bmod b)y_2
$$&lt;/p&gt;
&lt;p&gt;根据模的定义转换下，得：
$$
ax_1+by_1=bx_2+(a - \lfloor \dfrac{a}{b} \rfloor b)y_2
$$&lt;/p&gt;
&lt;p&gt;再转换。&lt;/p&gt;
&lt;p&gt;$$
ax_1+by_1=ay_2+b(x_2- \lfloor \dfrac{a}{b} \rfloor y_2)
$$&lt;/p&gt;
&lt;p&gt;现在，$x_1,y_1$ 可以通过 $x_2,y_2$ 来求了：&lt;/p&gt;
&lt;p&gt;$$
\begin{cases}
x_1 = y_2 \\
y1 = x_2- \lfloor \dfrac{a}{b} \rfloor y_2
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;而 $x_2,y_2$ 可以通过 $x_3,y_3$ 来求，而 $x_3,y_3$ 可以通过 $x_4,y_4$ 来求.....&lt;/p&gt;
&lt;p&gt;很容易想到，递归。&lt;/p&gt;
&lt;p&gt;我们把 $ax \equiv 1 \pmod p$ 转换一下，可得：&lt;/p&gt;
&lt;p&gt;$$
ax + py = 1
$$&lt;/p&gt;
&lt;p&gt;用扩展欧几里得算法求出 $x , y$，$x$ 就是 $a$ 在模 $p$ 意义下的逆元。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int exgcd(int a , int b){ //返回值是 gcd(a,b)
    if(b == 0){
        x = 1 , y = 0;
        return a;
    }
    int ret = exgcd(b , a % b);
    int tmp = x;
    x = y;
    y = tmp - (a / b) * y;
    return ret;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;inline pair &amp;lt;ll , ll&amp;gt; exgcd(ll a , ll b){ //不要gcd返回值
    if(b == 0) return make_pair(1 , 0);
    pair &amp;lt;ll , ll&amp;gt; ret = exgcd(b , a % b);
    return make_pair(ret.second , ret.first - (a / b) * ret.second);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;4. 欧拉函数&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;4.1定义：对于正整数 $n$。欧拉函数是小于 $n$ 的正整数中与 $n$ 互质的数的个数。表示为 $\varphi(n)$。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其中欧拉函数是积性函数。笔者证明很难。&lt;/p&gt;
&lt;p&gt;可以质因数分解来求。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;inline int phi(int x){
    int ret = x;
    for(int i = 2;i * i &amp;lt;= x;i++) if(x % i == 0){
        ret -= ret / i;
        while(x % i == 0) x /= i;
    }
    if(x &amp;gt; 1) ret -= ret / x;
    return x;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4.2. 性质&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;4.2.1：设 $x = y * p_i$。&lt;/p&gt;
&lt;p&gt;当 $x,y$ 均有质因子 $p_i$ 时，$\varphi(x) = \varphi(y) * p_i$。&lt;/p&gt;
&lt;p&gt;否则 $\varphi(x) = \varphi(y) * (p_i - 1)$。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;证明：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可通过其，用线性筛来求。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int ppp[500005] , phi[500005] , cnt;
bool vis[10000005];
inline void init(){
	phi[1] = 1;
	for(int i = 2;i &amp;lt;= 10000000;i++){
		if(!vis[i]) phi[i] = i - 1 , ppp[++cnt] = i;
		for(int j = 1;j &amp;lt;= cnt &amp;amp;&amp;amp; i * ppp[j] &amp;lt;= 10000000;j++){
			p[i * ppp[j]] = 1;
			if(i % ppp[j] == 0){
				phi[i * ppp[j]] = phi[i] * ppp[j];
				break;
			}
			phi[i * ppp[j]] = phi[i] * phi[ppp[j]];
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;4.2.2：$\gcd(x,y)=1,\varphi(xy)=\varphi(x)\varphi(y)$（积性函数）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;4.2.3：$\varphi(p^k)=p^{k-1}(p-1)$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;4.2.4：$\varphi(x)=\displaystyle\prod\varphi(p_i^k)=n\displaystyle\prod\dfrac{p_i-1}{p_i}$&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;5. 筛法&lt;/h1&gt;
&lt;h2&gt;5.1. 线性筛&lt;/h2&gt;
&lt;p&gt;$\mathcal O(n)$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;bool p[N];int ppp[N] , cnt;

void init(){
	for(int i = 2;i &amp;lt;= N;i++){
		if(!p[i]) ppp[++cnt] = i;
		for(int j = 1;j &amp;lt;= cnt &amp;amp;&amp;amp; ppp[j] * i &amp;lt;= N;j++){
			p[ppp[j] * i] = 1;
			if(i % ppp[j] == 0) break;
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以考虑预处理出比 $i$ 小的第一个质数，可以把分解质因数优化成 $O(\log n)$。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int i = 2;i &amp;lt;= N;i++){
  if(!vis[i]) ppp[++cnt] = i , minp[i] = i;
  for(int j = 1;j &amp;lt;= cnt &amp;amp;&amp;amp; ppp[j] * i &amp;lt;= N;j++){
    vis[ppp[j] * i] = 1;
    minp[ppp[j] * i] = min(minp[ppp[j]] , minp[i]);
    if(i % ppp[j] == 0) break;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;积性函数基本可以用线性筛求。&lt;/p&gt;
&lt;h2&gt;5.2. 埃氏筛&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;void init(){
	qwq[1] = 1;
	for(int i = 2;i &amp;lt;= n ;i++)
		if(!qwq[i])
			for(int j = i + i;j &amp;lt;= n;j += i)
				qwq[j] = 1;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5.3. 杜教筛&lt;/h2&gt;
&lt;p&gt;用于在非线性时间内求积性函数前缀和。&lt;/p&gt;
&lt;p&gt;假如求 $S(n) = \sum_{i=1}^n f(i)$。&lt;/p&gt;
&lt;p&gt;那么尝试找出一个合适的&lt;strong&gt;积性函数&lt;/strong&gt; $g$。它们的迪利克雷卷积的前缀和为：&lt;/p&gt;
&lt;p&gt;$$
\sum_{i=1}^n (f * g)(i)=\sum_{d=1}^n g(d)S(\lfloor \dfrac{n}{d} \rfloor)
$$&lt;/p&gt;
&lt;p&gt;那么 $g(1)S(n)=\sum_{i=1}^n (f * g)(i)-\sum_{d=2}^n g(d)S(\lfloor \dfrac{n}{d} \rfloor)$。&lt;/p&gt;
&lt;p&gt;代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int GetSum(int n) { // 算 f 前缀和的函数
	int ans = f_g_sum(n); // 算 f * g 的前缀和
	for(int l = 2 , r;l &amp;lt;= n;l = r + 1){ 
		r = n / (n / l); 
		ans -= (g_sum(r) - g_sum(l - 1)) * GetSum(n / l);// g_sum 是 g 的前缀和
	}
	return ans; 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;复杂度为 $O(n^{\frac{3}{4}})$。&lt;/p&gt;
&lt;h1&gt;6. 中国剩余定理&lt;/h1&gt;
&lt;p&gt;常用于求
$$
\begin{cases}
x\equiv r_1 \pmod {m_1} \
x\equiv r_2 \pmod {m_2} \
... \
x\equiv r_n \pmod {m_n} \
\end{cases}
$$
的最小可行解。&lt;/p&gt;
&lt;h2&gt;6.1. 求解&lt;/h2&gt;
&lt;p&gt;前提：$m$ 两两互质。&lt;/p&gt;
&lt;p&gt;核心思路是把求出 $n$ 个辅助解 $x_i$，每个 $x_i$ 满足：&lt;/p&gt;
&lt;p&gt;$$
\begin{cases}
x_i\equiv 0 \pmod {m_1} \
x_i\equiv 0 \pmod {m_2} \
... \
x_i\equiv 1 \pmod {m_i} \
...\
x_i\equiv 0 \pmod {m_n} \
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;最后的可行解就是：$\sum r_i x_i$。&lt;/p&gt;
&lt;p&gt;现在考虑求出每组 $x_i$。&lt;/p&gt;
&lt;p&gt;对于 $x_i$，设 $m_0$ 为可以整除 $x_i$ 的 $m$ 的乘积，于是我们可以知道：$x_i=pm_0=qm_i-1$。&lt;/p&gt;
&lt;p&gt;移项得：$qm_i-pm_0=1$。&lt;/p&gt;
&lt;p&gt;因为 $m_i,m_0$ 互质，所以有解（裴蜀定理），然后方程可以用扩欧求解，或者看成逆元也行。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;void exgcd(ll a , ll b){
	if(b == 0){
		x = 1 , y = 0;
		return ;
	}
	exgcd(b , a % b);
	ll tmp = x;
	x = y;
	y = tmp - (a / b) * y;
}

ll CRT(ll a[15] , ll m[15]){
	ll M = 1;
	for(int i = 1;i &amp;lt;= n;i++)
		M *= m[i];
	ll ret = 0;
	for(int i = 1;i &amp;lt;= n;i++){
		ll mmm = M / m[i];
		exgcd(mmm , m[i]);
		ll t = (x + m[i]) % m[i];
		ret += mmm * t * a[i] % M;
		ret %= M;
	}
	return (ret + M) % M;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6.2. exCRT&lt;/h2&gt;
&lt;p&gt;处理 $m$ 不互质的情况。&lt;/p&gt;
&lt;p&gt;可以考虑合并两个同余式子。有：&lt;/p&gt;
&lt;p&gt;$$
\begin{cases}
x\equiv r_1 \pmod {m_1} \
x\equiv r_2 \pmod {m_2} \
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;那么：$x=pm_1+r_1=qm_2+r_2$，移项得 $pm_1-qm_2=r_2-r_1$&lt;/p&gt;
&lt;p&gt;令 $d=\gcd(m_1,m_2)$，我们可以用 exgcd 求出方程 $a\frac{m_1}{d}+b\frac{m_2}{d}=\gcd(\frac{m_1}{d},\frac{m_2}{d})=1$ 的一组解，那么：&lt;/p&gt;
&lt;p&gt;$$
\begin{cases}
p=\dfrac{(r_2-r_1)a}{d} \
q=\dfrac{(r_1-r_2)b}{d} \
\end{cases}
$$&lt;/p&gt;
&lt;p&gt;于是 $x\equiv \dfrac{(r_2-r_1)a}{d} m_1+r_1 \pmod {\text{lcm}(m_1,m_2)}$，然后一个个合并直到剩下一个即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ll m0 , r0; scanf(&quot;%lld%lld&quot; , &amp;amp;m0 , &amp;amp;r0); n--;
while(n--){
    ll m , r; scanf(&quot;%lld%lld&quot; , &amp;amp;m , &amp;amp;r);
    ll t = lcm(m0 , m);
    ll d = __gcd(m0 , m);
    ll x = (exgcd(m0 / d , m / d).first + t) % t;
    r0 = (r0 + mul(mul((r - r0) / d , x , t) , m0 , t)) % t;
    m0 = t; //mul(a,b,MOD) 慢速乘
    r0 = (r0 + m0) % m0;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;7. 反演&lt;/h1&gt;
&lt;h2&gt;7.1. 莫比乌斯函数&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定义7.1.1：$\mu(n)=\left{\begin{array}{c}1, n=1\0, \exists p, n \equiv 0(\bmod p^2) \(-1)^{k}(k \text { 是 } n \text { 的质因子个数 })\end{array}\right.$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论7.1.2：$\sum_{d \mid n} \mu(d)=[n=1] \iff \mu * I=\epsilon$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;莫比乌斯函数为积性函数。&lt;/p&gt;
&lt;h2&gt;7.1.3. 莫比乌斯变换&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;形式a：$f(x)=\sum_{d|n}g(d)$，那么有 $g(n)=\sum_{d|n}\mu(d)f(\frac{n}{d})$&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;证明a：已知 $f=g&lt;em&gt;I$，欲证 $g=f&lt;/em&gt;\mu$
$f*\mu=g&lt;em&gt;I&lt;/em&gt;\mu=g*\epsilon=g$ 证毕。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;形式b：$f(x)=\sum_{n|d}g(d)$，那么有 $g(n)=\sum_{n|d}\mu(d)f(\frac{d}{n})$&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;7.2. 欧拉反演&lt;/h2&gt;
&lt;p&gt;$n=\sum_{d|n} \varphi(d)$&lt;/p&gt;
&lt;h2&gt;7.3. 反演技巧&lt;/h2&gt;
&lt;p&gt;构造函数强行反演：&lt;/p&gt;
&lt;p&gt;假如求 $\sum \sum f(\gcd(i,j))$&lt;/p&gt;
&lt;p&gt;那么提前求出所有 $f(i)$。&lt;/p&gt;
&lt;p&gt;再令 $f(i)=f(i)-\sum_{d|i &amp;amp; d \not= i} f(d)$&lt;/p&gt;
&lt;p&gt;于是 $f(i)=\sum_{d|i} f(d)$。&lt;/p&gt;
&lt;p&gt;下面给出模板 $O(n \ln n)$：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int i = 1;i &amp;lt;= N;i++) f[i] = xx; //预处理f
for(int i = 1;i &amp;lt;= N;i++) for(int j = i + i;j &amp;lt;= N;j += i)
    f[j] -= f[i];
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例题：&lt;/p&gt;
&lt;p&gt;P4449 于神之怒加强版&lt;/p&gt;
&lt;p&gt;$\sum \sum \gcd(i,j)^k$&lt;/p&gt;
&lt;p&gt;那么设 $f(x)=x^k$&lt;/p&gt;
&lt;p&gt;所以 $\sum \sum f(\gcd(i,j))$&lt;/p&gt;
&lt;p&gt;反演 $\sum \sum \sum_{d|\gcd(i,j)} f(d)$&lt;/p&gt;
&lt;p&gt;$\sum_{d=1}^nf(d) \lfloor \dfrac{n}{d}\rfloor \lfloor \dfrac{n}{d}\rfloor$&lt;/p&gt;
&lt;p&gt;预处理 $f$ 前缀和，数列分块求解。&lt;/p&gt;
&lt;p&gt;扩展：&lt;/p&gt;
&lt;p&gt;不是求和怎么办？？&lt;/p&gt;
&lt;p&gt;同理&lt;/p&gt;
&lt;p&gt;$f(i)=\dfrac{f(i)}{\prod_{d|i &amp;amp; d \not= i} f(d)}$&lt;/p&gt;
&lt;p&gt;于是 $f(i)=\prod_{d|i} f(d)$。&lt;/p&gt;
&lt;h1&gt;杂项&lt;/h1&gt;
&lt;h2&gt;a. 排列组合&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;定义a.1：$A_n^m$ 表示从 $n$ 里选 $m$ 个进行排列的方案数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定义a.2：$A_n^m = \dfrac{n!}{(n - m)!}$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定义a.3：$C_n^m$ 表示从 $n$ 中选 $m$ 个（不考虑顺序）的方案数。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;定义a.4：$C_n^m = \dfrac{A_n^m}{A_m^m} = \dfrac{n!}{m!(n - m)!}$&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;推论a.5：$C_n^m = C_{n - 1}^m + C_{n - 1}^{m - 1}$。不难发现，此乃杨辉三角。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;理论到实际&lt;/h3&gt;
&lt;h4&gt;zbj 问题&lt;/h4&gt;
&lt;p&gt;每个数值域为 $[1,m]$，$n$ 个数单增的数量为 $C_m^n$
不降的是 $C_{n+m-1}^{n-1}$。&lt;/p&gt;
&lt;p&gt;$n$ 个 zbj 放到 $m$ 个箱子中，每个箱子至少一个，$C_{n - 1}^{m-1}$。&lt;/p&gt;
&lt;p&gt;$n$ 个 zbj 放到 $m$ 个箱子中，可以先每个箱子放一个，所以$C_{n+m-1}^{m-1}$。&lt;/p&gt;
&lt;h2&gt;数论分块&lt;/h2&gt;
&lt;p&gt;用于求
$$\displaystyle\sum_{i=1}^{n} \lfloor \dfrac{n}{i}\rfloor$$&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;for(int l = 1 , r;l &amp;lt;= n;l = r + 1){
	r = n / (n / l);	
	ret += (r - l + 1) * (n / l);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;斐波那契数列&lt;/h2&gt;
&lt;h3&gt;定义&lt;/h3&gt;
&lt;p&gt;$$
F_0=0,F_1=1
$$&lt;/p&gt;
&lt;p&gt;$$
F_n=F_{n-1}+F_{n-2} \tag{1}
$$
$$
F_n=\dfrac{1}{\sqrt{5}}\bigg[\bigg(\dfrac{1+\sqrt{5}}{2}\bigg)^n - \bigg(\dfrac{1-\sqrt{5}}{2}\bigg)^n \bigg]
$$&lt;/p&gt;
&lt;h3&gt;推导&lt;/h3&gt;
&lt;p&gt;设
$$
F_n-\lambda F_{n-1}=\mu(F_{n-1}-\lambda F_{n-2}) \tag{2}
$$
$$
F_n=(\mu+\lambda) F_{n-1}-\mu\lambda F_{n-2}
$$
根据 $(1)$ 得：
$$
\begin{cases}
\mu+\lambda&amp;amp;=1 \
\mu \lambda&amp;amp;=-1
\end{cases}
$$
解得：
$$
\begin{cases}
\mu=\frac{1+\sqrt{5}}{2} \
\lambda=\frac{1-\sqrt{5}}{2}
\end{cases}
\quad or \quad
\begin{cases}
\mu=\frac{1-\sqrt{5}}{2} \
\lambda=\frac{1+\sqrt{5}}{2}
\end{cases}
$$
分别带回 $(2)$：
$$
\begin{cases}
F_n-\frac{1-\sqrt{5}}{2} F_{n-1}=\frac{1+\sqrt{5}}{2}(F_{n-1}-\frac{1-\sqrt{5}}{2} F_{n-2})\
F_n-\frac{1+\sqrt{5}}{2} F_{n-1}=\frac{1-\sqrt{5}}{2}(F_{n-1}-\frac{1+\sqrt{5}}{2} F_{n-2})
\end{cases}
$$
显然数列 ${F_n-\lambda F_{n-1}}$ 为等比数列，公差为 $\frac{1+\sqrt{5}}{2}$ 或 $\frac{1-\sqrt{5}}{2}$。则：
$$
\begin{cases}
F_n-\frac{1-\sqrt{5}}{2} F_{n-1}
=\bigg(F_2-\frac{1-\sqrt{5}}{2} F_{1}\bigg)\bigg(\dfrac{1+\sqrt{5}}{2}\bigg)^{n-1}
\quad&amp;amp;(3) \
F_n-\frac{1+\sqrt{5}}{2} F_{n-1}
=\bigg(F_2-\frac{1+\sqrt{5}}{2} F_{1}\bigg)\bigg(\dfrac{1-\sqrt{5}}{2}\bigg)^{n-1}
\quad&amp;amp;(4)
\end{cases}
$$
然后
$$
\dfrac{1+\sqrt{5}}{2} \times (3)-\dfrac{1-\sqrt{5}}{2} \times (4)
$$
得
$$
\sqrt{5}F_n=\bigg(\dfrac{1+\sqrt{5}}{2}\bigg)^{n}-\bigg(\dfrac{1-\sqrt{5}}{2}\bigg)^{n}
$$&lt;/p&gt;
&lt;p&gt;$$
F_n=\dfrac{1}{\sqrt{5}}\bigg[\bigg(\dfrac{1+\sqrt{5}}{2}\bigg)^{n}-\bigg(\dfrac{1-\sqrt{5}}{2}\bigg)^{n}\bigg]
$$&lt;/p&gt;
&lt;h2&gt;性质&lt;/h2&gt;
&lt;p&gt;由上可以发现：
$$
\begin{cases}
\mu=\frac{1}{\phi}=\frac{1+\sqrt{5}}{2} \
\lambda=\phi=\frac{1-\sqrt{5}}{2}
\end{cases}
\quad or \quad
\begin{cases}
\mu=\phi=\frac{1-\sqrt{5}}{2} \
\lambda=\frac{1}{\phi}=\frac{1+\sqrt{5}}{2}
\end{cases}
$$
（$\phi$ 指黄金分割比 $\dfrac{\sqrt{5}-1}{2}$）&lt;/p&gt;
&lt;p&gt;所以通项公式可以写成：
$$
F_n=\dfrac{1}{\sqrt{5}}\bigg(\phi^{-n}-\phi^{n}\bigg)
$$&lt;/p&gt;
&lt;h2&gt;时间复杂度相关&lt;/h2&gt;
&lt;h3&gt;代换法&lt;/h3&gt;
&lt;p&gt;$T(n)=2T(\lfloor \frac{n}{2} \rfloor)+n$&lt;/p&gt;
&lt;p&gt;直觉
$$
T(n)\le c n \log_2 n
$$
所以
$$
T(\lfloor \frac{n}{2} \rfloor)\le c \lfloor \frac{n}{2} \rfloor \log_2 \lfloor \frac{n}{2} \rfloor
$$
带回原式
$$
T(n)\le 2c \lfloor \frac{n}{2} \rfloor \log_2 \lfloor \frac{n}{2} \rfloor+n\le cn \log_2 \frac{n}{2} +n\
=cn\log_2 n - cn + n \le cn\log_2 n
$$
$c\ge 1$ 时成立。&lt;/p&gt;
&lt;h2&gt;主公式&lt;/h2&gt;
&lt;h3&gt;内容&lt;/h3&gt;
&lt;h3&gt;证明&lt;/h3&gt;
&lt;h2&gt;小公式&lt;/h2&gt;
&lt;p&gt;$(a+b)^3 =(a^2+ab)(a+b)+(ab+b^2)(a+b)=a^3+b^3+3a^2b+3ab^2$&lt;/p&gt;
&lt;p&gt;$(a-b)^3 =a^3-b^3-3a^2b+3ab^2$&lt;/p&gt;
&lt;p&gt;$a^3+b^3=(a+b)(a^2-ab+b^2)$&lt;/p&gt;
&lt;p&gt;$a^3-b^3=(a-b)(a^2+ab+b^2)$&lt;/p&gt;
&lt;p&gt;$(a+b)^n = \displaystyle\sum_{k = 0}^nC^n_kx^{n-k}y^k = \displaystyle\sum_{k = 0}^nC^n_k x^{k}y^{n-k}$&lt;/p&gt;
&lt;p&gt;$\displaystyle\sum_{i=1}^n i^2=\dfrac{n(n+1)(2n+1)}{6}$&lt;/p&gt;
&lt;p&gt;$\displaystyle\sum_{i=1}^n i^3=\dfrac{(n + 1)^2n^2}{4}$&lt;/p&gt;
&lt;p&gt;当 $n$ 是正奇数时&lt;/p&gt;
&lt;p&gt;$a^n+b^n=(a+b)(a^{n-1}-a^{n-2}b+a^{n-3}b^2-...-ab^{n-2}+b^{n-1})$&lt;/p&gt;
&lt;p&gt;对于 $f(x)=a_nx^n+a_{n-1}x^{n-1}+...+a_1x+a_0$&lt;/p&gt;
&lt;p&gt;当 $f(c)=0$ 时，设有理数根 $c=\dfrac{p}{q}$（$p,q$ 互质）。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://imgse.com/i/pFh7YGT&quot;&gt;&lt;img src=&quot;https://s21.ax1x.com/2024/03/23/pFh7YGT.png&quot; alt=&quot;pFh7YGT.png&quot; /&gt;&lt;/a&gt;
$x-c$ 除 $f(x)$ 时，余数是 $f(c)$。&lt;/p&gt;
</content:encoded></item><item><title>（线段）树学是怎样炼成的</title><link>https://qwq-senlin.cc.cd/post/OI-seg/</link><guid isPermaLink="true">https://qwq-senlin.cc.cd/post/OI-seg/</guid><description>你要成为线段树少女吗？</description><pubDate>Mon, 20 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;我喜欢打线段树。&lt;/p&gt;
&lt;p&gt;特别是动态开点线段树。每一次与线段树相见，我总觉得是受了上天的眷顾与恩惠。&lt;/p&gt;
&lt;p&gt;那些动态开点线段树，114、514年地活在世上，那要经历多少、怎样的时光？&lt;/p&gt;
&lt;p&gt;打线段树，线段树当然不会改变，但看打得久了，打线段树的人不由自主地有了变化——把自己看成了一棵线段树。&lt;/p&gt;
&lt;p&gt;线段树不再是“他”，而在不知不觉中变成了“你”。&lt;/p&gt;
&lt;p&gt;线段树已经成为独特的具体，有他的前世今生，成了相对于我的“你”。线段树也有自我意识吧，那样，我也可以妄想成为线段树的“你”，我和你！我用眼睛听你，用耳朵看你，用“心”换意念，去揣摩你。&lt;/p&gt;
&lt;p&gt;想当年，不知是何人栽下了你，或者只是IOer遗落了一粒灵感、无心长成了你？1e114514199810谔谔年来，你经历了太多的朝代更迭，多少TLE、MLE，那都不算什么。&lt;/p&gt;
&lt;p&gt;多少WA、TLE、OLE、MLE、UKE，你是怎么活下来的？此处在Luogu，古代应该人迹罕至、人为破坏不易。TLE因旁有n&amp;lt;=1e8，T掉你的机会减少；扎根处在宽阔的Luogu，MLE不能把你卡。&lt;/p&gt;
&lt;p&gt;“高坡OJ上，尽是毒瘤翁。人人尽怀卡常意，不见AC映屏幕绿”，你是怎样幸运地一次次躲过了UKE之灾？&lt;/p&gt;
&lt;p&gt;根仍在汲取，叶仍在吐纳，题面和数据一定是永不停歇地和你进行着交流互动。&lt;/p&gt;
&lt;p&gt;“南方水阔，北地风多”，一年又一年风的OLE，都未能拿你奈何。&lt;/p&gt;
&lt;p&gt;四周山峦逶迤，线段树木葱茏，long long 来过，线段树声哼吼，贯通肺腑。懂线段树的朋友说，这里一定有充足的评测资源，你四处探路的根须早已与CPU接通，至少1e114514199810谔谔年来从未枯竭。&lt;/p&gt;
&lt;p&gt;古线段树从来不是孤独的，你一定不是单个的存在。&lt;/p&gt;
&lt;p&gt;这里的线段树活得长，有风气、有遗传。在树状树祖直线距离不到两公里的地方还有一棵年龄相仿的线段树。大慨是在历史上受了unsigned long long，那棵线段树只有半个部分还活着，活着的半个部分倒也是生机盎然。&lt;/p&gt;
&lt;p&gt;时间虽然已经过去了1e114514199810谔谔年，这样的情形似乎以后也不会改变。想象你们的未来，我有担忧，居然也有信心。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;主要参考：lxl 课件&lt;/p&gt;
&lt;p&gt;本文所讲的线段树题，仅包括思路重点在线段树的题，而不是用线段树优化什么。&lt;/p&gt;
&lt;p&gt;其实硬要把线段树和扫描线分开是不可能的，这就是「我中有你，你中有我」。&lt;/p&gt;
&lt;p&gt;因此这里例题放那边实际上是&lt;strong&gt;重点偏向哪边&lt;/strong&gt;，并不是不用另一方的。&lt;/p&gt;
&lt;h1&gt;线段树&lt;/h1&gt;
&lt;h2&gt;标记信息的设计&lt;/h2&gt;
&lt;p&gt;本节参考：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.me/article/rqmfqvmu&quot;&gt;https://www.luogu.me/article/rqmfqvmu&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/Meatherm/p/17925813.html#:~:text=%E5%A6%82%E6%9E%9C%E6%89%80%E6%9C%89%E4%BF%A1%E6%81%AF%E9%83%BD%E5%8F%AF%E4%BB%A5%E8%A2%AB%E8%A1%A8%E7%A4%BA%E4%B8%BA%E8%A1%8C%E6%95%B0%E7%9B%B8%E5%90%8C%E7%9A%84%E5%88%97%E5%90%91%E9%87%8F%20x%20x%EF%BC%8C%E5%90%88%E5%B9%B6%E4%BF%A1%E6%81%AF%E5%8F%AF%E4%BB%A5%E8%A1%A8%E7%A4%BA%E4%B8%BA%E5%90%91%E9%87%8F%E5%8A%A0%E6%B3%95%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%A0%87%E8%AE%B0%E4%BD%9C%E7%94%A8%E5%9C%A8%E4%BF%A1%E6%81%AF%E4%B8%8A%E5%8F%AF%E4%BB%A5%E7%94%A8%E7%9F%A9%E9%98%B5%20A%20A,%E6%9D%A5%E6%8F%8F%E8%BF%B0%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E7%A7%8D%E6%A0%87%E8%AE%B0%20%2F%20%E4%BF%A1%E6%81%AF%E5%BD%A2%E5%BC%8F%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8F%8C%E5%8D%8A%E7%BE%A4%E6%A8%A1%E5%9E%8B%EF%BC%9A%E8%A1%8C%E6%95%B0%E7%9B%B8%E5%90%8C%E7%9A%84%E5%88%97%E5%90%91%E9%87%8F%E5%AF%B9%E5%8A%A0%E6%B3%95%E6%9E%84%E6%88%90%E4%BA%A4%E6%8D%A2%E7%BE%A4%EF%BC%8C%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95%E6%BB%A1%E8%B6%B3%E7%BB%93%E5%90%88%E5%BE%8B%E4%B8%94%E5%AD%98%E5%9C%A8%E5%8D%95%E4%BD%8D%E7%9F%A9%E9%98%B5%20I%20I%EF%BC%8C%E5%B9%B6%E4%B8%94%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95%E5%AF%B9%E7%9F%A9%E9%98%B5%E5%8A%A0%E6%B3%95%E4%B9%9F%E6%98%AF%E5%A4%A9%E7%84%B6%E6%BB%A1%E8%B6%B3%E5%88%86%E9%85%8D%E5%BE%8B%E7%9A%84%E3%80%82%20%E5%B8%B8%E8%A7%81%E7%9A%84%E7%9F%A9%E9%98%B5%E6%9C%89%E4%B8%A4%E7%A7%8D%E3%80%82&quot;&gt;https://www.cnblogs.com/Meatherm/p/17925813.html#:~&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;线段树基本原则（信息&amp;amp;标记）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;信息+信息-&amp;gt;信息（区间合并pushup）&lt;/li&gt;
&lt;li&gt;标记+标记-&amp;gt;标记（tag合并）&lt;/li&gt;
&lt;li&gt;标记+信息-&amp;gt;信息（tag可对信息作用pushdown）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以从维护信息出发，推出其他信息和标记。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;例：小白&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单点加&lt;/li&gt;
&lt;li&gt;区间查最大子段和&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于查询，显然信息要维护最大子段和，于是考虑第一点。&lt;/p&gt;
&lt;p&gt;一个大区间显然是由左右小区间合并上了，于是为了合并它，就需要再维护前缀最大值和后缀最大值。&lt;/p&gt;
&lt;p&gt;由于是单点修改，并不需要标记。&lt;/p&gt;
&lt;p&gt;以上可以写成模板，不用的线段树只有三个函数有差别。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
using namespace std;

struct Tag {
	//标记h 
	Tag(){}
	inline friend Tag operator + (Tag l , Tag r){
		//信息合并（相当于pushup） 
	}
	inline void operator += (Tag t){
		(*this) = (*this) + t;
	}
}tag[400005];

struct Seg {
	//信息 
	inline friend Seg operator + (Seg ls , Seg rs){
		//标记作用标记 
	}
	inline void operator += (Tag t){
		//标记作用信息 
	}
}tr[400005];

inline void pushdown(int p){
	if(){ //判断标记非空 
		tr[p &amp;lt;&amp;lt; 1] += tag[p]; tr[p &amp;lt;&amp;lt; 1 | 1] += tag[p];
		tag[p &amp;lt;&amp;lt; 1] += tag[p]; tag[p &amp;lt;&amp;lt; 1 | 1] += tag[p];
		tag[p] = Tag();
	}
}

void init(int p , int l , int r){
	if(l == r){ return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

void upd(int p , int l , int r , int x , int y , Tag k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){ tr[p] += k; tag[p] += k; return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) + 
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;从扫描线到历史版本和&lt;/h2&gt;
&lt;p&gt;其实这边都是关于历史的。&lt;/p&gt;
&lt;p&gt;一般的这种题，可以考虑将 l 做横轴，r 做纵轴，这样就成了矩形查询，区间修改，这玩意一般需要用到历史版本和。&lt;/p&gt;
&lt;p&gt;我们很容易可以设计出信息和标记，但是问题就在于如何合并。&lt;/p&gt;
&lt;p&gt;有的可能要考虑很多种情况，这里给出一种比较好用的方法：矩阵。&lt;/p&gt;
&lt;p&gt;实际上可以把信息标记都放在矩阵上，那么就变成矩阵乘法。写出矩阵后，一般大多项都是固定没用的，于是可以把变的提出来，暴力解出转移，这样便有了标记的转移方式，这还可以尝试合并相同的值，大多数情况下这样跑出来的转移是和按照实际意义推的转移是相同的。&lt;/p&gt;
&lt;p&gt;以下是暴力转移的代码（待办：用python写一个功能更完整的）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;cstring&amp;gt;
using namespace std;

int n;
struct QWQ{ char a[105][105][10]; QWQ(){ memset(a , 0 , sizeof(a)); } }A , B;

inline void mul_max(QWQ x , QWQ y){ //M为负无穷 
	for(int i = 1;i &amp;lt;= n;i++)
		for(int j = 1;j &amp;lt;= n;j++){
			int flag = 0;
			for(int k = n;k &amp;gt;= 1;k--)
				if(x.a[i][k][1] != &apos;M&apos; &amp;amp;&amp;amp; y.a[k][j][1] != &apos;M&apos;){ flag = k; break; }
			if(!flag) continue;
			printf(&quot;(%d %d)=max(&quot; , i , j);
			for(int k = 1;k &amp;lt;= n;k++){
				if(x.a[i][k][1] == &apos;M&apos; || y.a[k][j][1] == &apos;M&apos;) continue;
				printf(&quot;%s+%s&quot; , x.a[i][k] + 1 , y.a[k][j] + 1);
				if(k != flag) putchar(&apos;,&apos;);
			}
			putchar(&apos;)&apos;); putchar(&apos;\n&apos;);
		}
}

inline void mul_(QWQ x , QWQ y){
	for(int i = 1;i &amp;lt;= n;i++)
		for(int j = 1;j &amp;lt;= n;j++){
			int flag = 0;
			for(int k = n;k &amp;gt;= 1;k--)
				if(x.a[i][k][1] != &apos;0&apos; &amp;amp;&amp;amp; y.a[k][j][1] != &apos;0&apos;){ flag = k; break; }
			if(!flag) continue;
			printf(&quot;ret.k[1] = &quot;);
			for(int k = 1;k &amp;lt;= n;k++){
				if(x.a[i][k][1] == &apos;0&apos; || y.a[k][j][1] == &apos;0&apos;) continue;
				printf(&quot; %s * %s&quot; , x.a[i][k] + 1 , y.a[k][j] + 1);
				if(k != flag) printf(&quot; +&quot;);
			}
			printf(&quot;;\n&quot;);
		}
}

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++)
		for(int j = 1;j &amp;lt;= n;j++)
			scanf(&quot;%s&quot; , A.a[i][j] + 1);
	for(int i = 1;i &amp;lt;= n;i++)
		for(int j = 1;j &amp;lt;= n;j++)
			scanf(&quot;%s&quot; , B.a[i][j] + 1);
	mul_(A , B);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后操作如果有涉及到 max 等的东西，可以考虑使用$ (\max,+) $矩阵，就是吧矩乘的$ \times $改成$ + $，$ + $改成$ \max $。&lt;/p&gt;
&lt;p&gt;不过如果题目的操作过于复杂，其实没必要使用暴力转移找不变，可以直接矩乘，只是常数较大。&lt;/p&gt;
&lt;h3&gt;NOIP2022比赛&lt;/h3&gt;
&lt;p&gt;看了好几遍题解，没看懂。。。（以下是自己想的，因为题解看不懂。。）&lt;/p&gt;
&lt;p&gt;考虑第$ i $个点什么时候能对答案有贡献，显然，当且仅当区间包含$ i $，且满足$ l &amp;gt; L_i,r &amp;lt; R_i $，其中$ L_i $表示第$ i $个点左边第一个大于$ a_i $的位置，$ R_i $同理。于是这样，每个点都变成一个矩形：$ [L_i+1,i,i,R_i-1] $。&lt;/p&gt;
&lt;p&gt;这样处理完，就有两个二维平面$ a,b $，答案就是$ [l,r,l,r] $矩形内$ a \times b $的和。&lt;/p&gt;
&lt;p&gt;但是。。。&lt;/p&gt;
&lt;p&gt;扫描线怎么维护？？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;矩形$ a $赋值。&lt;/li&gt;
&lt;li&gt;矩形$ b $赋值。&lt;/li&gt;
&lt;li&gt;求矩形$ a \times b  $的值。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;？？？赋值怎么测回。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;stack&amp;gt;
#include &amp;lt;queue&amp;gt;
using namespace std;
typedef unsigned long long ll;

int T , n , a[250005] , b[250005];
int la[250005] , ra[250005] , lb[250005] , rb[250005];
ll ans[250005]; 

struct Seg { ll s , xy , x , y; }tr[1000005];

struct Tag { ll tx , ty , adx , ady , adxy , adc; }tag[1000005];

inline void pushup(int p){ //信息+信息 
	tr[p].s = tr[p &amp;lt;&amp;lt; 1].s + tr[p &amp;lt;&amp;lt; 1 | 1].s;
	tr[p].xy = tr[p &amp;lt;&amp;lt; 1].xy + tr[p &amp;lt;&amp;lt; 1 | 1].xy;
	tr[p].x = tr[p &amp;lt;&amp;lt; 1].x + tr[p &amp;lt;&amp;lt; 1 | 1].x;
	tr[p].y = tr[p &amp;lt;&amp;lt; 1].y + tr[p &amp;lt;&amp;lt; 1 | 1].y;
}

inline void tag_info(Seg &amp;amp;ret , Tag t , int le){ //标记作用信息 
	ret.s += ret.xy * t.adxy + ret.x * t.adx + ret.y * t.ady + le * t.adc;
	if(t.tx &amp;amp;&amp;amp; t.ty){
		ret.xy = le * t.tx * t.ty;
		ret.x = le * t.tx;
		ret.y = le * t.ty;
	}
	else if(t.tx){
		ret.xy = ret.y * t.tx;
		ret.x = le * t.tx;
	}
	else if(t.ty){
		ret.xy = ret.x * t.ty;
		ret.y = le * t.ty; 
	}
} 

inline void tag_tag(Tag &amp;amp;ret , Tag t){ //标记作用标记 
	if(ret.tx &amp;amp;&amp;amp; ret.ty){
		
	}
	else if(ret.tx){
		
	}
	else if(ret.ty){
		
	}
	else{
		ret.adx += t.adx;
		ret.ady += t.ady;
		ret.adxy += t.adxy;
		ret.adc += t.adc;
	}
	if(t.tx) ret.tx = t.tx;
	if(t.ty) ret.ty = t.ty;
}

struct Line {
	int x , y1 , y2 , k , id;
	bool operator &amp;lt; (const Line &amp;amp;b) const {
		if(x == b.x){
			if(id &amp;lt; 0 &amp;amp;&amp;amp; b.id &amp;lt; 0) return k &amp;lt; b.k;
			else return id &amp;gt; b.id;
		}
		return x &amp;lt; b.x;
	}
}qwq[1000005]; int cnt;

inline void init(){
	stack &amp;lt;pair &amp;lt;int , int&amp;gt; &amp;gt; tmp;
	scanf(&quot;%d%d&quot; , &amp;amp;T , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%d&quot; , &amp;amp;a[i]);
		while(!tmp.empty() &amp;amp;&amp;amp; tmp.top().first &amp;lt; a[i]) tmp.pop();
		if(!tmp.empty()) la[i] = tmp.top().second;
		tmp.push(make_pair(a[i] , i));
	}
	while(!tmp.empty()) tmp.pop();
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%d&quot; , &amp;amp;b[i]);
		while(!tmp.empty() &amp;amp;&amp;amp; tmp.top().first &amp;lt; b[i]) tmp.pop();
		if(!tmp.empty()) lb[i] = tmp.top().second;
		tmp.push(make_pair(b[i] , i));
	}
	for(int i = 1;i &amp;lt;= n;i++){
		qwq[++cnt] = (Line){i , la[i] + 1 , i , a[i] , -1};
		qwq[++cnt] = (Line){i , lb[i] + 1 , i , b[i] , -2};
	}
	scanf(&quot;%d&quot; , &amp;amp;T);
	for(int i = 1 , l , r;i &amp;lt;= T;i++){
		scanf(&quot;%d%d&quot; , &amp;amp;l , &amp;amp;r);
		qwq[++cnt] = (Line){l , l , r , -1 , i};
		qwq[++cnt] = (Line){r + 1 , l , r , 1 , i};
	}
}

int main(void){
	init();
//	printf(&quot;qw%llu\n&quot; , (ll)(-1) * query(1 , 1 , n , 1 , 2));
//	tr[1].updad(1);
//	upd2(1 , 1 , n , 1 , 1 , 1);
//	upd1(1 , 1 , n , 1 , 1 , 2);
//	tr[1].updad(1);
//	printf(&quot;qw%llu\n&quot; , query(1 , 1 , n , 1 , 2));
//	upd2(1 , 1 , n , 1 , 2 , 2);
//	upd1(1 , 1 , n , 2 , 2 , 1);
//	tr[1].updad(1);
//	printf(&quot;qw%llu\n&quot; , (ll)(1) * query(1 , 1 , n , 1 , 2));
//	return 0;
	sort(qwq + 1 , qwq + 1 + cnt);
	for(int i = 1;i &amp;lt;= cnt;i++){
		printf(&quot;%d %d %d %d %d\n&quot; , qwq[i].x , qwq[i].k , qwq[i].y1 , qwq[i].y2 , qwq[i].id); 
		if(qwq[i].x != qwq[i - 1].x) tr[1].updad(qwq[i].x - qwq[i - 1].x);
		if(qwq[i].id &amp;lt; 0){
			if(qwq[i].id == -1) upd1(1 , 1 , n , qwq[i].y1 , qwq[i].y2 , qwq[i].k);
			if(qwq[i].id == -2) upd2(1 , 1 , n , qwq[i].y1 , qwq[i].y2 , qwq[i].k);
		}
		else{
			ans[qwq[i].id] += (ll)qwq[i].k * query(1 , 1 , n , qwq[i].y1 , qwq[i].y2);
			printf(&quot;%llu\n&quot; , (ll)qwq[i].k * query(1 , 1 , n , qwq[i].y1 , qwq[i].y2));
		}
			
	}
	for(int i = 1;i &amp;lt;= T;i++) printf(&quot;%llu\n&quot; , ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;我已从 CPU 大成归来。&lt;/p&gt;
&lt;p&gt;冯sir 说不需要撤回，于是问题变成：&lt;/p&gt;
&lt;p&gt;$ a $或 $ b $区间推平，求$ \sum a_ib_i $的历史和。&lt;/p&gt;
&lt;p&gt;去掉历史和是平凡的，这里信息很容易看出来：$ a $的和，$ b $的和，$ ab $的和，历史和（答案），区间长度。&lt;/p&gt;
&lt;p&gt;以上记为$ x,y,xy,s,le $&lt;/p&gt;
&lt;p&gt;直接暴力矩阵！！！！！！！！！！！！！！！！！！&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}x\y\xy\s\le \end{bmatrix} \begin{bmatrix}0&amp;amp;0&amp;amp;0&amp;amp;0&amp;amp;0\0&amp;amp;1&amp;amp;k&amp;amp;0&amp;amp;0\0&amp;amp;0&amp;amp;0&amp;amp;0&amp;amp;0\0&amp;amp;0&amp;amp;0&amp;amp;1&amp;amp;0\k&amp;amp;0&amp;amp;0&amp;amp;0&amp;amp;1 \end{bmatrix}=\begin{bmatrix}kle\y\ky\s\le \end{bmatrix}  $&lt;/p&gt;
&lt;p&gt;另外一个推平同理。&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}x\y\xy\s\le \end{bmatrix} \begin{bmatrix}1&amp;amp;0&amp;amp;0&amp;amp;0&amp;amp;0\0&amp;amp;1&amp;amp;0&amp;amp;0&amp;amp;0\0&amp;amp;0&amp;amp;1&amp;amp;1&amp;amp;0\0&amp;amp;0&amp;amp;0&amp;amp;1&amp;amp;0\0&amp;amp;0&amp;amp;0&amp;amp;0&amp;amp;1 \end{bmatrix}=\begin{bmatrix}xle\y\xy\s+xy\le \end{bmatrix}  $&lt;/p&gt;
&lt;p&gt;然后这个是把答案加到历史和里的。&lt;/p&gt;
&lt;p&gt;然后用上面的暴力程序多乘几次，发现除去$ 1,0 $就只有$ 12 $种可能的值，我们维护它，然后再用暴力程序跑一遍，暴力跑出转移式子，直接复制上去即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;stack&amp;gt;
using namespace std;
typedef unsigned long long ll;

struct Tag {
	ll k[12];
	inline Tag(){ k[0]=k[3]=k[6]=1;k[1]=k[2]=k[4]=k[5]=k[7]=k[8]=k[9]=k[10]=k[11]=0; }
		
	inline Tag(int a0 , int a1 , int a2 , int a3 , int a4 , int a5 , int a6 , int a7 , int a8 , int a9 , int a10 , int a11){k[0]=a0;k[1]=a1;k[2]=a2;k[3]=a3;k[4]=a4;k[5]=a5;k[6]=a6;k[7]=a7;k[8]=a8;k[9]=a9;k[10]=a10;k[11]=a11;}
		
	inline Tag friend operator + (Tag l , Tag r) {
		Tag ret;
		ret.k[0] =  l.k[0] * r.k[0];
		ret.k[1] =  l.k[0] * r.k[1] + l.k[1] * r.k[6];
		ret.k[2] =  l.k[0] * r.k[2] + l.k[1] * r.k[7] + l.k[2];
		ret.k[3] =  l.k[3] * r.k[3];
		ret.k[4] =  l.k[3] * r.k[4] + l.k[4] * r.k[6];
		ret.k[5] =  l.k[3] * r.k[5] + l.k[4] * r.k[7] + l.k[5];
		ret.k[6] =  l.k[6] * r.k[6];
		ret.k[7] =  l.k[6] * r.k[7] + l.k[7];
		ret.k[8] =  l.k[8] * r.k[0] + r.k[8];
		ret.k[9] =  l.k[9] * r.k[3] + r.k[9];
		ret.k[10] =  l.k[8] * r.k[1] + l.k[9] * r.k[4] + l.k[10] * r.k[6] + r.k[10];
		ret.k[11] =  l.k[8] * r.k[2] + l.k[9] * r.k[5] + l.k[10] * r.k[7] + l.k[11] + r.k[11];
		return ret;
	}

	inline void operator += (Tag x) { (*this) = (*this) + x; }
	
	inline bool zbj(){ return k[0]!=1||k[3]!=1||k[6]!=1||k[1]||k[2]||k[4]||k[5]||k[7]||k[8]||k[9]||k[10]||k[11]; }
}lazy[1000005];

struct Seg {
	ll x , y , xy , s , le;
	inline Seg friend operator + (Seg l , Seg r){
		return (Seg){
			l.x + r.x , l.y + r.y , l.xy + r.xy ,
			l.s + r.s , l.le + r.le
		};
	}
	inline void operator += (Tag p){
		(*this) = (Seg){
			x * p.k[0] + le * p.k[8] ,
			y * p.k[3] + le * p.k[9] ,
			x * p.k[1] + y * p.k[4] + xy * p.k[6] + le * p.k[10] ,
			x * p.k[2] + y * p.k[5] + xy * p.k[7] + le * p.k[11] + s , 
			le
		};
	}
}tr[1000005];

void init(int p , int l , int r){
	tr[p].le = r - l + 1;
	if(l == r) return ; 
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
}

inline void pushdown(int p){
	if(lazy[p].zbj()){
		tr[p &amp;lt;&amp;lt; 1] += lazy[p]; tr[p &amp;lt;&amp;lt; 1 | 1] += lazy[p];
		lazy[p &amp;lt;&amp;lt; 1] += lazy[p]; lazy[p &amp;lt;&amp;lt; 1 | 1] += lazy[p];
		lazy[p] = Tag();
	}
}

void upd(int p , int l , int r , int x , int y , Tag k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){ tr[p] += k; lazy[p] += k; return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k); 
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) +
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

//void print(int p , int l , int r){
//	printf(&quot;(%d %d %d)%llu %llu\n&quot; , p , l , r , tr[p].xy , tr[p].s);
//	if(l == r) return ;	
//	int mid = (l + r) &amp;gt;&amp;gt; 1;
//	pushdown(p);
//	print(p &amp;lt;&amp;lt; 1 , l , mid); print(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
//	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
//}

int T , n , a[250005] , b[250005] , la[250005] , lb[250005];

struct QWQ { int l , r , k , op; };
vector &amp;lt;QWQ&amp;gt; chm[250005] , qqq[250005];

ll ans[250005];



int main(void){
	scanf(&quot;%d%d&quot; , &amp;amp;T , &amp;amp;n);
	init(1 , 1 , n);
	stack &amp;lt;pair &amp;lt;int , int&amp;gt; &amp;gt; tmp;
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%d&quot; , &amp;amp;a[i]);
		while(!tmp.empty() &amp;amp;&amp;amp; tmp.top().first &amp;lt; a[i]) tmp.pop();
		if(!tmp.empty()) la[i] = tmp.top().second;
		tmp.push(make_pair(a[i] , i));
	}
	while(!tmp.empty()) tmp.pop();
	for(int i = 1;i &amp;lt;= n;i++){
		scanf(&quot;%d&quot; , &amp;amp;b[i]);
		while(!tmp.empty() &amp;amp;&amp;amp; tmp.top().first &amp;lt; b[i]) tmp.pop();
		if(!tmp.empty()) lb[i] = tmp.top().second;
		tmp.push(make_pair(b[i] , i));
	}
	for(int i = 1;i &amp;lt;= n;i++){
		chm[i].push_back((QWQ){la[i] + 1 , i , a[i] , 0});
		chm[i].push_back((QWQ){lb[i] + 1 , i , b[i] , 1});
	}
	scanf(&quot;%d&quot; , &amp;amp;T);
	for(int i = 1 , l , r;i &amp;lt;= T;i++){
		scanf(&quot;%d%d&quot; , &amp;amp;l , &amp;amp;r);
		qqq[l - 1].push_back((QWQ){l , r , -1 , i});
		qqq[r].push_back((QWQ){l , r , 1 , i});
	}
	for(int i = 1;i &amp;lt;= n;i++){
		for(QWQ j : chm[i]){
			if(j.op) upd(1 , 1 , n , j.l , j.r , Tag(1 , j.k , 0 , 0 , 0 , 0 , 0 , 0 , 0 , j.k , 0 , 0));
			if(!j.op)upd(1 , 1 , n , j.l , j.r , Tag(0 , 0 , 0 , 1 , j.k , 0 , 0 , 0 , j.k , 0 , 0 , 0));
		}
//		printf(&quot;%llu %llu\n&quot; , tr[1].xy , tr[1].s);
		upd(1 , 1 , n , 1 , n , Tag(1 , 0 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 0 , 0));
//		printf(&quot;%llu %llu\n&quot; , tr[1].xy , tr[1].s);
//		print(1 , 1 , n);
		for(QWQ j : qqq[i])
			ans[j.op] += j.k * query(1 , 1 , n , j.l , j.r).s;
	}
	for(int i = 1;i &amp;lt;= T;i++) printf(&quot;%llu\n&quot; , ans[i]);
}

//inline Tag(ll a1 , ll a2 , ll a4 , ll a5 , ll a7 , ll a8): k11(a1) , k12(a2) , k21(a4) , k22(a5) , k31(a7) , k32(a8
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;P3246 序列&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;求区间内所有子区间的最小值的和&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我发现类似这种子区间的最值可以按如下思路思考：&lt;/p&gt;
&lt;p&gt;比如有 $ 5,2,4,1 ,3 $，那么：&lt;/p&gt;
&lt;p&gt;5 2 4 1 3                 5 2 2 1 1&lt;/p&gt;
&lt;p&gt;2 4 1 3                    2 2 1 1&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  4 1 3  -----&amp;gt;           4 1 1

     1 3                          1 1

        3                             3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以发现是一个矩形，扫描线，且不需要撤回，后边的矩形会直接覆盖前面的。&lt;/p&gt;
&lt;p&gt;然后就可以考虑每个点在对什么区间是有贡献的。&lt;/p&gt;
&lt;p&gt;设$ pre,nxt $意思显然&lt;/p&gt;
&lt;p&gt;因此每个矩形就是$ [pre + 1 , i , i , nxt - 1] $，&lt;/p&gt;
&lt;p&gt;由于是直接覆盖的，nxt 不需要考虑&lt;/p&gt;
&lt;p&gt;pre 用单调栈即可，后面的用扫描线离线做。&lt;/p&gt;
&lt;p&gt;于是问题变成：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;a区间推平，求历史区间的和&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;历史和&lt;s&gt;只会&lt;/s&gt;用矩阵。信息很容易知道，就是区间和$ s $，区间历史和$ b $，于是：&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}s\b \ le\end{bmatrix}\begin{bmatrix}0&amp;amp;0&amp;amp;0\0&amp;amp;1&amp;amp;0 \ k&amp;amp;0&amp;amp;1\end{bmatrix}=\begin{bmatrix}k\times le\b \ le\end{bmatrix} $&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}s\b \ le\end{bmatrix}\begin{bmatrix}1&amp;amp;1&amp;amp;0\0&amp;amp;1&amp;amp;0 \ 0&amp;amp;0&amp;amp;1\end{bmatrix}=\begin{bmatrix}s\b+s \ le\end{bmatrix} $&lt;/p&gt;
&lt;p&gt;用暴力矩乘得出只有四个位置是有值的。直接再跑一次得转移即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;stack&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
typedef long long ll;

struct Tag {
	ll k1 , k2 , k3 , k4;
	inline Tag(){k1 = 1; k2 = k3 = k4 = 0; }
	inline Tag(int _ , int __ , int ___ , int ____): k1(_) , k2(__) , k3(___) , k4(____) {}
	inline friend Tag operator + (Tag l , Tag r){
		Tag ret;
		ret.k1 = l.k1 * r.k1;
		ret.k2 = l.k1 * r.k2 + l.k2;
		ret.k3 = l.k3 * r.k1 + r.k3;
		ret.k4 = l.k3 * r.k2 + l.k4 + r.k4;
		return ret;
	}
	inline void operator += (Tag x){
		(*this) = (*this) + x;
	}
}lz[400005];

struct Seg {
	ll s , b; int le;
	inline Seg(){ s = b = le = 0; }
	inline friend Seg operator + (Seg l , Seg r){
		Seg ret;
		ret.s = l.s + r.s;
		ret.b = l.b + r.b;
		ret.le = l.le + r.le;
		return ret;
	}
	inline void operator += (Tag x){
		b += x.k2 * s + x.k4 * le;
		s = x.k1 * s + x.k3 * le;
	}
}tr[400005];

inline void upd(int p , Tag x){ tr[p] += x; lz[p] += x; }

inline void pushdown(int p){
	if(lz[p].k1 == 1 &amp;amp;&amp;amp; lz[p].k2 == 0 &amp;amp;&amp;amp; lz[p].k3 == 0 &amp;amp;&amp;amp; lz[p].k4 == 0) return ;
	upd(p &amp;lt;&amp;lt; 1 ,  lz[p]);
	upd(p &amp;lt;&amp;lt; 1 | 1 , lz[p]);
	lz[p] = (Tag){1 , 0 , 0 , 0};
}

void upd(int p , int l , int r , int x , int y , Tag k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) { upd(p , k); return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) + 
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

void init(int p , int l , int r){
	if(l == r){ tr[p].s = tr[p].b = 0; tr[p].le = 1; return ;}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

int n , q , a[100005] , pre[100005];

struct QWQ { int l , r , k , op; };
vector &amp;lt;QWQ&amp;gt; uuu[200005] , qqq[100005];

ll ans[100005];

void solve(){
	init(1 , 1 , n);
	stack &amp;lt;pair &amp;lt;int , int&amp;gt; &amp;gt; tmp;
	for(int i = 1;i &amp;lt;= n;i++){
		while(!tmp.empty() &amp;amp;&amp;amp; tmp.top().first &amp;gt; a[i]) tmp.pop();
		if(!tmp.empty()) pre[i] = tmp.top().second;
		tmp.push({a[i] , i});
	}
	for(int i = 1;i &amp;lt;= n;i++)
		uuu[i].push_back((QWQ){pre[i] + 1 , i , a[i] , 0});
	for(int i = 1;i &amp;lt;= q;i++){
		int l , r; scanf(&quot;%d%d&quot; , &amp;amp;l , &amp;amp;r);
		qqq[l - 1].push_back((QWQ){l , r , -1 , i});
		qqq[r].push_back((QWQ){l , r , 1 , i});
	}
	for(int i = 1;i &amp;lt;= n;i++){
		for(QWQ j : uuu[i]) upd(1 , 1 , n , j.l , j.r , Tag(0 , 0 , j.k , 0));
		upd(1 , Tag(1 , 1 , 0 , 0));
		for(QWQ j : qqq[i])
			ans[j.op] += 1LL * j.k * query(1 , 1 , n , j.l , j.r).b;
	}
	for(int i = 1;i &amp;lt;= q;i++) printf(&quot;%lld\n&quot; , ans[i]);
}

int main(void){
	scanf(&quot;%d%d&quot; , &amp;amp;n , &amp;amp;q);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;a[i]);
	solve();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CF997E &amp;amp; 猫猫贴贴&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;给定一个排列，多次询问，求区间内子区间有多少是取值连续的 $ n,q\le 1.2 \times 10^5 $&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;毒瘤题，十年河东十年河西，莫欺少年穷。&lt;/p&gt;
&lt;p&gt;首先排列很重要，意味着取值不重复，于是取值连续的区间需要满足$ \max-\min=r-l $，即$ \max-\min-r+l=0 $。&lt;/p&gt;
&lt;p&gt;按照扫描线的思路，放到二维平面上，横 l，纵 r，先把每个点权值改为$ l-r $，这个是简单的，可以转换成区间加。&lt;/p&gt;
&lt;p&gt;然后考虑更新$ \min $和$ \max $，如果可以问题就变成矩形求$ 0 $的个数，因为$ 0\le \max-\min-r+l $，所以这玩意可以用最小值和最小值的个数维护。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;stack&amp;gt;
using namespace std;

struct Tag {
	int ad , tg;
	inline Tag(){ ad = tg = 0; }
	inline Tag(int _ , int __): ad(_) , tg(__) {}
	inline void operator += (Tag b){ ad += b.ad; tg += b.tg; }
}lz[480005];

struct Seg {
	int mi , cntmi; long long ans;
	inline friend Seg operator + (Seg ls , Seg rs){
		Seg ret;
		if(ls.mi &amp;lt; rs.mi){
			ret.mi = ls.mi;
			ret.cntmi = ls.cntmi;
		}
		else if(ls.mi &amp;gt; rs.mi){
			ret.mi = rs.mi;
			ret.cntmi = rs.cntmi;
		}
		else{
			ret.mi = ls.mi;
			ret.cntmi = ls.cntmi + rs.cntmi;
		}
		ret.ans = ls.ans + rs.ans;
		return ret;
	}
//	inline void operator += (Tag x){
//		mi += x.ad;
//		ans += 1LL * cntmi * x.tg;
//	}
}tr[480005];

inline void upd(int p , Tag x , int tmp){
	lz[p].ad += x.ad;
	if((tr[p].mi += x.ad) == tmp){
		tr[p].ans += 1LL * x.tg * tr[p].cntmi;
		lz[p].tg += x.tg;
	}
}

inline void pushdown(int p){
	if(lz[p].ad == 0 &amp;amp;&amp;amp; lz[p].tg == 0) return ;
	upd(p &amp;lt;&amp;lt; 1 , lz[p] , tr[p].mi);
	upd(p &amp;lt;&amp;lt; 1 | 1 , lz[p] , tr[p].mi);
	lz[p] = Tag(0 , 0);
}

void upd(int p , int l , int r , int x , int y , Tag k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){ upd(p , k , 0); return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1, l , mid , x , y);
	if(x &amp;gt; mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) + 
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

void init(int p , int l , int r){
	if(l == r){ tr[p].cntmi = 1; return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

int n , m , p[120005];
int lx[120005] , rx[120005] , li[120005] , ri[120005];

struct QWQ { int l , r , k , id; };
vector &amp;lt;QWQ&amp;gt; u[120005] , q[120005];

inline void solve(int retl[120005] , int retr[120005] , bool (*cmp)(int , int)){
	stack &amp;lt;pair &amp;lt;int , int&amp;gt; &amp;gt; st;
	for(int i = 1;i &amp;lt;= n;i++){
		while(!st.empty() &amp;amp;&amp;amp; cmp(st.top().first , p[i])) st.pop();
		retl[i] = st.empty()? 0 : st.top().second;
		st.push({p[i] , i});
	}
	while(!st.empty()) st.pop();
	for(int i = n;i &amp;gt;= 1;i--){
		while(!st.empty() &amp;amp;&amp;amp; cmp(st.top().first , p[i])) st.pop();
		retr[i] = st.empty()? n + 1 : st.top().second;
		st.push({p[i] , i});
	}
}

long long ans[120005];

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;p[i]);
	scanf(&quot;%d&quot; , &amp;amp;m);
	for(int i = 1;i &amp;lt;= m;i++){
		int l , r; scanf(&quot;%d%d&quot; , &amp;amp;l , &amp;amp;r);
		q[l - 1].push_back((QWQ){l , r , -1 , i});
		q[r].push_back((QWQ){l , r , 1 , i});
	}
	solve(lx , rx , [](int x , int y) -&amp;gt; bool {return x &amp;lt; y; });
	solve(li , ri , [](int x , int y) -&amp;gt; bool {return x &amp;gt; y; });
	for(int i = 1;i &amp;lt;= n;i++){
		u[lx[i] + 1].push_back((QWQ){i , rx[i] - 1 , p[i] , 0});
		u[i + 1].push_back((QWQ){i , rx[i] - 1 , -p[i] , 0});
		u[li[i] + 1].push_back((QWQ){i , ri[i] - 1 , -p[i] , 0});
		u[i + 1].push_back((QWQ){i , ri[i] - 1 , p[i] , 0});
	}
	for(int i = 1;i &amp;lt;= n;i++){
		u[i].push_back((QWQ){1 , n , 1 , 0});
		u[1].push_back((QWQ){i , i , -i , 0});
	}
	init(1 , 1 , n);
	for(int i = 1;i &amp;lt;= n;i++){
		for(QWQ j : u[i]) upd(1 , 1 , n , j.l , j.r , Tag(j.k , 0));
		upd(1 , Tag(0 , 1) , 0);
		for(QWQ j : q[i]) ans[j.id] += 1LL * j.k * query(1 , 1 , n , j.l , j.r).ans;
	}
	for(int i = 1;i &amp;lt;= m;i++) printf(&quot;%lld\n&quot; , ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;P9990 Ynoi Easy Round 2023 TEST_90 &amp;amp; P10822&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;多次询问区间的所有子区间有多少满足出现数字个数是奇数&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先可以转换成区间内所有子区间的数字个数对 2 取模的和。&lt;/p&gt;
&lt;p&gt;一般的，区间出现个数可以用$ \sum [pre_i &amp;lt; l] $来计算，根据这个我们很容易写出矩形：$ [pre_i+1,i,i,n] $&lt;/p&gt;
&lt;p&gt;发现区间增加 1 实际上就是异或 1，于是需要线段树实现区间异或，求历史区间和。&lt;/p&gt;
&lt;p&gt;有点困难，考虑用矩阵思考下。&lt;/p&gt;
&lt;p&gt;维护的显然就是区间 1 的数量$ a $，历史区间和$ b $。于是：&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}a\b \ le\end{bmatrix}\begin{bmatrix}-1&amp;amp;0&amp;amp;0\0&amp;amp;1&amp;amp;0 \ 1&amp;amp;0&amp;amp;1\end{bmatrix}=\begin{bmatrix}le-a\b \ le\end{bmatrix} $&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}a\b \ le\end{bmatrix}\begin{bmatrix}1&amp;amp;1&amp;amp;0\0&amp;amp;1&amp;amp;0 \ 0&amp;amp;0&amp;amp;1\end{bmatrix}=\begin{bmatrix}a\a+b \ le\end{bmatrix} $&lt;/p&gt;
&lt;p&gt;又到了暴力转移的时候。&lt;/p&gt;
&lt;p&gt;这方法常数有点大。。。。要卡常（最好不用vector）&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

char buf[1 &amp;lt;&amp;lt; 21] , *p1 , *p2;
#define GC p1 == p2 &amp;amp;&amp;amp; (p2 = (p1 = buf) + fread(buf , 1 , 1 &amp;lt;&amp;lt; 21 , stdin) , p1 == p2) ? EOF : *p1++
inline int read() {
	int x = 0; char ch = GC;
	while(ch &amp;gt; &apos;9&apos; || ch &amp;lt; &apos;0&apos;) ch = GC;
	while(ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;){ x = (x &amp;lt;&amp;lt; 1) + (x &amp;lt;&amp;lt; 3) + (ch ^ 48); ch = GC; }
	return x; 
}

struct Tag {
	int k1 , k3 , k2 , k4;
	inline Tag(){ k1 = 1; k2 = k3 = k4 = 0; }
	inline Tag(int _ , int __ , int ___ , int ____): k1(_) , k2(__) , k3(___) , k4(____) {}
	inline friend Tag operator + (Tag l , Tag r){
		return Tag(
			l.k1 * r.k1 ,
			l.k1 * r.k2 + l.k2 , 
			l.k3 * r.k1 + r.k3 ,
			l.k3 * r.k2 + l.k4 + r.k4
		);
	}
	inline void operator += (Tag x){ (*this) = (*this) + x; }
}lz[4000005];

struct Seg {
	int a , le; long long b;
	inline Seg(){ a = b = le = 0; }
	inline Seg(int _ , long long __ , int ___): a(_) , b(__) , le(___) {}
	inline friend Seg operator + (Seg ls , Seg rs){
		return Seg(ls.a + rs.a , ls.b + rs.b , ls.le + rs.le);
	}
	inline void operator += (Tag x){
		(*this) = Seg(x.k1 * a + x.k3 * le , 1LL * x.k2 * a + b + 1LL * x.k4 * le , le);
	}
}tr[4000004];

inline void pushdown(int p){
	if(lz[p].k1 == 1 &amp;amp;&amp;amp; lz[p].k2 == 0 &amp;amp;&amp;amp; lz[p].k3 == 0 &amp;amp;&amp;amp; lz[p].k4 == 0) return ;
	tr[p &amp;lt;&amp;lt; 1] += lz[p]; lz[p &amp;lt;&amp;lt; 1] += lz[p];
	tr[p &amp;lt;&amp;lt; 1 | 1] += lz[p]; lz[p &amp;lt;&amp;lt; 1 | 1] += lz[p];
	lz[p] = Tag();
}

void upd(int p , int l , int r , int x , int y , Tag k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){
		tr[p] += k; lz[p] += k;
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) + 
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

void init(int p , int l , int r){ //
	if(l == r){ tr[p].le = 1; return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

int n , m , pre[1000005];
struct QWQ {
	int x , l , r , k , id;
	inline bool operator &amp;lt; (QWQ b) {
		if(x == b.x) return id &amp;lt; b.id;
		return x &amp;lt; b.x;
	}
}qqq[4000005]; int qn;
long long ans[1000005];

int main(void){
	n = read();
	for(int i = 1 , a;i &amp;lt;= n;i++){
		a = read();
		qqq[i] = (QWQ){pre[a] + 1 , i , n , 0 , 0};
		qqq[i + n] = (QWQ){i + 1 , i , n , 0 , 0};
		pre[a] = i;
	}
	m = read();
	qn = (n &amp;lt;&amp;lt; 1);
	for(int i = 1;i &amp;lt;= m;i++){
		int l , r; l = read(); r = read();
		qqq[++qn] = (QWQ){l - 1 , l , r , 0 , i};
		qqq[++qn] = (QWQ){r , l , r , 1 , i};
	}
	sort(qqq + 1 , qqq + 1 + qn);
	init(1 , 1 , n);
	int i = 1;
	while(i &amp;lt;= qn){
		int st = qqq[i].x;
		while(i &amp;lt;= qn &amp;amp;&amp;amp; qqq[i].x == st &amp;amp;&amp;amp; qqq[i].id == 0)
			upd(1 , 1 , n , qqq[i].l , qqq[i].r , Tag(-1 , 0 , 1 , 0)) , i++;
		tr[1] += Tag(1 , 1 , 0 , 0); lz[1] += Tag(1 , 1 , 0 , 0);
		while(i &amp;lt;= qn &amp;amp;&amp;amp; qqq[i].x == st)
			ans[qqq[i].id] += qqq[i].k? query(1 , 1 , n , qqq[i].l , qqq[i].r).b : -query(1 , 1 , n , qqq[i].l , qqq[i].r).b , i++;
	}
	for(int i = 1;i &amp;lt;= m;i++) printf(&quot;%lld\n&quot; , ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;区间最值操作与历史最值问题&lt;/h2&gt;
&lt;p&gt;本节参考：&lt;/p&gt;
&lt;p&gt;论文《区间最值操作与历史最值问题》——吉如一&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/rfalvjih&quot;&gt;区间最值操作与区间历史最值详解 灵梦&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;oi-wki&lt;/p&gt;
&lt;h3&gt;区间最值操作&lt;/h3&gt;
&lt;p&gt;实现区间取最值的一种方法。（下以取最小值为例）&lt;/p&gt;
&lt;p&gt;区间维护区间最大值（mx），严格次大值（mx2），最大值的个数（cnt）。&lt;/p&gt;
&lt;p&gt;然后区间操作（$ a_i=\min(x,a_i) $）有如下情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$ mx \le x $：直接退出&lt;/li&gt;
&lt;li&gt;$ mx2 &amp;lt; x \le mx $：仅修改最大值，打标记。&lt;/li&gt;
&lt;li&gt;$ x\le mx2 $：递归下去。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;论文证明复杂度为$ O(\log n) $。&lt;/p&gt;
&lt;p&gt;然后如果加上区间加的操作，实现类似，复杂度变为$ O(\log^2 n) $。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;深挖上面那种方法的本质，实际上就是&lt;strong&gt;分类&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;将点分成两类：最大值和非最大值。&lt;/p&gt;
&lt;p&gt;于是另一种实现区间取最值的方法呼吁而出。&lt;/p&gt;
&lt;p&gt;仅修改最大值，那么就是推平操作，可以转换成加操作。&lt;/p&gt;
&lt;p&gt;标记需要两套：最大的加标记，非最大值的加标记。&lt;/p&gt;
&lt;p&gt;于是这种方法便实现了：区间取最值-&amp;gt;区间加&lt;/p&gt;
&lt;p&gt;这种思路很有启发性。&lt;/p&gt;
&lt;h4&gt;最佳女选手&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;区间加，区间取最大值，区间取最小值，求区间和，求区间最大最小&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;类比：如果同时有取最大和取最小的操作，那么可以分三类。最大，最小，其他。&lt;/p&gt;
&lt;p&gt;按照上面方法维护即可，注意合并函数里的细节。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
typedef long long ll;

const ll inf = 1e17;

char buf[1 &amp;lt;&amp;lt; 21] , *p1 , *p2;
#define GC p1 == p2 &amp;amp;&amp;amp; (p2 = (p1 = buf) + fread(buf , 1 , 1 &amp;lt;&amp;lt; 21 , stdin) , p1 == p2) ? EOF : *p1++
inline int read() {
	int x = 0;
    bool f = false;
	char ch = GC;
	while(ch &amp;gt; &apos;9&apos; || ch &amp;lt; &apos;0&apos;){
        if(ch == &apos;-&apos;)
            f = true;
        ch = GC;
    }
	while(ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;){
		x = (x &amp;lt;&amp;lt; 1) + (x &amp;lt;&amp;lt; 3) + (ch ^ 48);
		ch = GC;
	}
	return f? -x : x; 
}

struct Tag {
	ll admx , admi , ad;
	inline void operator += (Tag b){ admx += b.admx; admi += b.admi; ad += b.ad; }
}tg[2000005];

struct Seg {
	ll mx , mx2; int cntmx;
	ll mi , mi2; int cntmi;
	ll sum; int le;
	
	inline friend Seg operator + (Seg ls , Seg rs){
		Seg ret;
		if(ls.mx &amp;gt; rs.mx){
			ret.mx = ls.mx; ret.cntmx = ls.cntmx;
			ret.mx2 = max(ls.mx2 , rs.mx);
		}
		else if(ls.mx &amp;lt; rs.mx){
			ret.mx = rs.mx; ret.cntmx = rs.cntmx;
			ret.mx2 = max(ls.mx , rs.mx2);
		}
		else{
			ret.mx = ls.mx; ret.cntmx = ls.cntmx + rs.cntmx;
			ret.mx2 = max(ls.mx2 , rs.mx2);
		}
		if(ls.mi &amp;lt; rs.mi){
			ret.mi = ls.mi; ret.cntmi = ls.cntmi;
			ret.mi2 = min(ls.mi2 , rs.mi);
		}
		else if(ls.mi &amp;gt; rs.mi){
			ret.mi = rs.mi; ret.cntmi = rs.cntmi;
			ret.mi2 = min(ls.mi , rs.mi2);
		}
		else {
			ret.mi = ls.mi; ret.cntmi = ls.cntmi + rs.cntmi;
			ret.mi2 = min(ls.mi2 , rs.mi2);
		}
		ret.sum = ls.sum + rs.sum;
		ret.le = ls.le + rs.le;
		return ret;
	}

	inline void operator += (Tag x){
		if(mx == mi) sum += x.admx * cntmx;
		else sum += x.admx * cntmx + x.admi * cntmi + x.ad * (le - cntmx - cntmi);
		if(mi2 == mx) mi2 += x.admx;
		else if(mi2 !=  inf) mi2 += x.ad;
		if(mx2 == mi) mx2 += x.admi;
		else if(mx2 != -inf) mx2 += x.ad;
		mx += x.admx; mi += x.admi;
	}
}tr[2000005];

inline void upd(int p , Tag x){
	if(tr[p].mx == tr[p].mi){
		if(x.admi == x.ad) x.admi = x.admx;
		else x.admx = x.admi;
	}
	tr[p] += x; tg[p] += x;
}

inline void pushdown(int p){
	if(tg[p].ad == 0 &amp;amp;&amp;amp; tg[p].admx == 0 &amp;amp;&amp;amp; tg[p].admi == 0) return ;
	ll mx = max(tr[p &amp;lt;&amp;lt; 1].mx , tr[p &amp;lt;&amp;lt; 1 | 1].mx);
	ll mi = min(tr[p &amp;lt;&amp;lt; 1].mi , tr[p &amp;lt;&amp;lt; 1 | 1].mi);
	upd(p &amp;lt;&amp;lt; 1 , (Tag){
		tr[p &amp;lt;&amp;lt; 1].mx == mx? tg[p].admx : tg[p].ad ,
		tr[p &amp;lt;&amp;lt; 1].mi == mi? tg[p].admi : tg[p].ad ,
		tg[p].ad
	});
	upd(p &amp;lt;&amp;lt; 1 | 1 , (Tag){
		tr[p &amp;lt;&amp;lt; 1 | 1].mx == mx? tg[p].admx : tg[p].ad ,
		tr[p &amp;lt;&amp;lt; 1 | 1].mi == mi? tg[p].admi : tg[p].ad ,
		tg[p].ad
	});
	tg[p] = (Tag){0 , 0 , 0};
}

int a[500005];
void init(int p , int l , int r){
	if(l == r){
		tr[p].mx2 = -inf; tr[p].mi2 = inf;
		tr[p].sum = tr[p].mx = tr[p].mi = a[l];
		tr[p].cntmx = tr[p].cntmi = 1;
		tr[p].le = 1;
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

void upd1(int p , int l , int r , int x , int y , Tag k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){ upd(p , k); return ; }
	pushdown(p);
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	upd1(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd1(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

void upd_max(int p , int l , int r , int x , int y , int k){
	if(l &amp;gt; y || r &amp;lt; x || tr[p].mi &amp;gt;= k) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y &amp;amp;&amp;amp; k &amp;lt; tr[p].mi2){
		upd(p , (Tag){0 , k - tr[p].mi , 0});
		return ;
	}
	pushdown(p);
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	upd_max(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd_max(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

void upd_min(int p , int l , int r , int x , int y , int k){
	if(l &amp;gt; y || r &amp;lt; x || tr[p].mx &amp;lt;= k) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y &amp;amp;&amp;amp; k &amp;gt; tr[p].mx2){
		upd(p , (Tag){k - tr[p].mx , 0 , 0});
		return ;
	}
	pushdown(p);
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	upd_min(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd_min(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	pushdown(p);
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid ) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) + 
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

int n , m;

int main(void){
	n = read();
	for(int i = 1;i &amp;lt;= n;i++) a[i] = read();
	init(1 , 1 , n);
	m = read();
	while(m--){
		int op , l , r;
		op = read(); l = read(); r = read();
		if(op == 1){
			int x = read();
			upd1(1 , 1 , n , l , r , (Tag){x , x , x});
		}
		if(op == 2){
			int x = read();
			upd_max(1 , 1 , n , l , r , x);
		}
		if(op == 3){
			int x = read();
			upd_min(1 , 1 , n , l , r , x);
		}
		if(op == 4) printf(&quot;%lld\n&quot; , query(1 , 1 , n , l , r).sum);
		if(op == 5) printf(&quot;%lld\n&quot; , query(1 , 1 , n , l , r).mx);
		if(op == 6) printf(&quot;%lld\n&quot; , query(1 , 1 , n , l , r).mi);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;盟誓的文艺复兴&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/problem/T496408&quot;&gt;this&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;区间取最值，区间求有几个子区间的最大值等于大区间的最大值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我之前出的，很水，其实重点在三操作，不过三操作也简单。不说。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
typedef long long ll;

int id , T;
int a[100005];
int n , m;
const int inf = 0x7fffffff;

struct Tree {
	int maxn , maxsum , secondmax;
	int minn , secondmin; 
	pair &amp;lt;int , int &amp;gt; mintag , maxtag;
	ll twt;
	int maxl , maxr;
	inline void min_upd(pair &amp;lt;int , int&amp;gt; t){
		if(t.first &amp;lt; maxn){
			if(secondmin == maxn)
				secondmin = t.first;
			maxn = t.first;
			if(secondmax == -inf)
				minn = t.first;
			mintag = t;
		}
	}
	inline void max_upd(pair &amp;lt;int , int&amp;gt; t){
		if(t.first &amp;gt; minn){
			if(secondmax == minn)
				secondmax = t.first;
			minn = t.first;
			if(secondmin == inf)
				maxn = t.first;
			maxtag = t;
		}
	}
}qwq[400005];

inline ll square(int x){ return 1LL * x * x; }

inline Tree merge(int l , int r , int mid , Tree ls , Tree rs){
	Tree ret;
	ret.maxtag = ret.mintag = {-inf , 0};
	if(ls.maxn &amp;gt; rs.maxn){
		ret.maxn = ls.maxn;
		ret.maxsum = ls.maxsum;
		ret.secondmax = max(ls.secondmax , rs.maxn);
		ret.maxl = ls.maxl;
		ret.maxr = ls.maxr;
		ret.twt = (
			ls.twt - square(mid - ls.maxr) +
			square(r - ls.maxr)
		);
	}
	if(ls.maxn &amp;lt; rs.maxn){
		ret.maxn = rs.maxn;
		ret.maxsum = rs.maxsum;
		ret.secondmax = max(rs.secondmax , ls.maxn);
		ret.maxl = rs.maxl;
		ret.maxr = rs.maxr;
		ret.twt = (
			rs.twt - square(rs.maxl - mid - 1) +
			square(rs.maxl - l)
		);
	}
	if(ls.maxn == rs.maxn){
		ret.maxn = ls.maxn;
		ret.maxsum = ls.maxsum + rs.maxsum;
		ret.secondmax = max(ls.secondmax , rs.secondmax);
		ret.maxl = ls.maxl;
		ret.maxr = rs.maxr;
		ret.twt = (
			(ls.twt - square(mid - ls.maxr)) +
			(rs.twt - square(rs.maxl - mid - 1)) +
			square(rs.maxl - ls.maxr - 1)
		);
	}

	if(ls.minn &amp;lt; rs.minn){
		ret.minn = ls.minn;
		ret.secondmin = min(ls.secondmin , rs.minn);
	}
	if(ls.minn &amp;gt; rs.minn){
		ret.minn = rs.minn;
		ret.secondmin = min(rs.secondmin , ls.minn);
	}
	if(ls.minn == rs.minn){
		ret.minn = ls.minn;
		ret.secondmin = min(ls.secondmin , rs.secondmin);
	}
	return ret;
}

inline void pushdown(int p){
	if(qwq[p].mintag.first != -inf &amp;amp;&amp;amp; qwq[p].maxtag.first != -inf){
		if(qwq[p].mintag.second &amp;lt; qwq[p].maxtag.second){
			qwq[p &amp;lt;&amp;lt; 1].max_upd(qwq[p].maxtag);
			qwq[p &amp;lt;&amp;lt; 1 | 1].max_upd(qwq[p].maxtag);
			qwq[p].maxtag = {-inf , 0};
			qwq[p &amp;lt;&amp;lt; 1].min_upd(qwq[p].mintag);
			qwq[p &amp;lt;&amp;lt; 1 | 1].min_upd(qwq[p].mintag);
			qwq[p].mintag = {-inf , 0};
		}
		else{
			qwq[p &amp;lt;&amp;lt; 1].min_upd(qwq[p].mintag);
			qwq[p &amp;lt;&amp;lt; 1 | 1].min_upd(qwq[p].mintag);
			qwq[p].mintag = {-inf , 0};
			qwq[p &amp;lt;&amp;lt; 1].max_upd(qwq[p].maxtag);
			qwq[p &amp;lt;&amp;lt; 1 | 1].max_upd(qwq[p].maxtag);
			qwq[p].maxtag = {-inf , 0};
		}
		return ;
	}
	if(qwq[p].mintag.first != -inf){
		qwq[p &amp;lt;&amp;lt; 1].min_upd(qwq[p].mintag);
		qwq[p &amp;lt;&amp;lt; 1 | 1].min_upd(qwq[p].mintag);
		qwq[p].mintag = {-inf , 0};
	}
	if(qwq[p].maxtag.first != -inf){
		qwq[p &amp;lt;&amp;lt; 1].max_upd(qwq[p].maxtag);
		qwq[p &amp;lt;&amp;lt; 1 | 1].max_upd(qwq[p].maxtag);
		qwq[p].maxtag = {-inf , 0};
	}
}

void init(int p , int l , int r){
	if(l == r){
		qwq[p].maxtag = qwq[p].mintag = {-inf , 0};
		qwq[p].maxn = qwq[p].minn = a[l];
		qwq[p].maxsum = 1;
		qwq[p].secondmax = -inf;
		qwq[p].secondmin = inf;
		qwq[p].maxl = qwq[p].maxr = l;
		qwq[p].twt = 0;
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid);
	init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	qwq[p] = merge(l , r , mid , qwq[p &amp;lt;&amp;lt; 1] , qwq[p &amp;lt;&amp;lt; 1 | 1]);
}

void minupd(int p , int l , int r , int x , int y , int k){
	if(l &amp;gt; y || r &amp;lt; x)
		return ;
	if(k &amp;gt;= qwq[p].maxn)
		return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y &amp;amp;&amp;amp; k &amp;gt; qwq[p].secondmax){ //只改最�?
		if(qwq[p].maxn == qwq[p].secondmin)
			qwq[p].secondmin = k;
		qwq[p].maxn = k;
		if(qwq[p].secondmax == -inf)
			qwq[p].minn = k;
		qwq[p].mintag = {k , m};
		return ;
	}
	pushdown(p);
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	minupd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	minupd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	qwq[p] = merge(l , r , mid , qwq[p &amp;lt;&amp;lt; 1] , qwq[p &amp;lt;&amp;lt; 1 | 1]);
}

void maxupd(int p , int l , int r , int x , int y , int k){
	if(l &amp;gt; y || r &amp;lt; x)
		return ;
	if(k &amp;lt;= qwq[p].minn)
		return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y &amp;amp;&amp;amp; k &amp;lt; qwq[p].secondmin){
		if(qwq[p].minn == qwq[p].secondmax)
			qwq[p].secondmax = k;
		qwq[p].minn = k;
		if(qwq[p].secondmin == inf)
			qwq[p].maxn = k;
		qwq[p].maxtag = {k , m};
		return ;
	}
	pushdown(p);
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	maxupd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	maxupd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	qwq[p] = merge(l , r , mid , qwq[p &amp;lt;&amp;lt; 1] , qwq[p &amp;lt;&amp;lt; 1 | 1]);
}

Tree solve3(int p , int l , int r , int x , int y){
	if(l &amp;gt; y || r &amp;lt; x)
		return (Tree){0 , 0 , 0 , 0 , 0 , {0 , 0} , {0 , 0} , 0 , 0 , 0};
	// printf(&quot;twt%lld %d %d\n&quot; , qwq[p].twt , l , r);
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y)
		return qwq[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	Tree ls = solve3(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	Tree rs = solve3(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	if(ls.maxsum == 0)
		return rs;
	if(rs.maxsum == 0)
		return ls;
	return merge(max(x , l) , min(y , r) , mid , ls , rs); //
}

void DEBUG(int p , int l , int r){
	if(l == r){
		printf(&quot;%d &quot; , qwq[p].maxn);
		return ;
	}
	pushdown(p);
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	DEBUG(p &amp;lt;&amp;lt; 1 , l , mid);
	DEBUG(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
}

inline int read() {
	int x = 0;
	bool f = false;
	char ch = getchar();
	while(ch &amp;gt; &apos;9&apos; || ch &amp;lt; &apos;0&apos;){
        if(ch == &apos;-&apos;)
            f = true;
        ch = getchar();
	}
	while(ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;){
		x = (x &amp;lt;&amp;lt; 1) + (x &amp;lt;&amp;lt; 3) + (ch ^ 48);
		ch = getchar();
	}
	return f? -x : x; 
}

int main(void){
	id = read(); T = read(); 
	while(T--){
		ll kkk = 0;
		n = read(); m = read();
		for(int i = 1;i &amp;lt;= n;i++) a[i] = read();
		init(1 , 1 , n);
		while(m--){
			int op , l , r , x , y;
			op = read(); l = read(); r = read();
			if(id &amp;amp; 1){
				l = ((1LL * l * l) ^ kkk) % n * 2333 % n + 1;
				r = ((1LL * r * r) ^ kkk) % n * 2024 % n + 1;
				if(l &amp;gt; r) swap(l , r);
			}
			if(op == 1){
				x = read();
				minupd(1 , 1 , n , l , r , x);
			}
			if(op == 2){
				x = read();
				maxupd(1 , 1 , n , l , r , x);
			}
			if(op == 3){
				Tree ret = solve3(1 , 1 , n , l , r);
				ll ans = 1LL * (r - l + 1) * (r - l + 2);
				ans -= ret.twt + (r - l + 1 - ret.maxsum);
				ans &amp;gt;&amp;gt;= 1;
				printf(&quot;%lld\n&quot; , ans);
				kkk = ans;
			}
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;历史最值问题&lt;/h3&gt;
&lt;p&gt;前置：复杂标记信息合并。&lt;/p&gt;
&lt;p&gt;一般这种可以用$ (\max,+) $矩阵来设计标记，如果再加上区间最值操作呢？直接看模板把。&lt;/p&gt;
&lt;h4&gt;线段树3&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;区间加，区间取min，求区间和，区间最大值，历史区间最大值&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;还是按照上面思路分两类：最大，非最大。上面说了可以转换成加法，于是考虑如何维护。&lt;/p&gt;
&lt;p&gt;这里还是使用矩阵（&lt;s&gt;由于不会直接推&lt;/s&gt;）。&lt;/p&gt;
&lt;p&gt;显然信息就是区间最大值 a，历史最大 b（这里历史最值和区间和无关，分别维护）。这样。&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix} a\b \end{bmatrix}\begin{bmatrix} x &amp;amp; x\-\infty&amp;amp; 0 \end{bmatrix}=\begin{bmatrix} a+x\\max{b,a+x} \end{bmatrix} $&lt;/p&gt;
&lt;p&gt;让我们暴力拆拆拆。&lt;/p&gt;
&lt;p&gt;暴力程序跑出来，显然只需要维护矩阵的第一行两项即可，然后再跑矩阵转移即可。&lt;/p&gt;
&lt;p&gt;然后就写完了。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
typedef long long ll;

const int inf = 2e9;

struct Tag {
	int k1 , k2; //最大值
	int k3 , k4; //非最大 
	inline Tag(){ k1 = k2 = k3 = k4 = 0; }
	inline Tag(ll _ , ll __ , ll ___ , ll ____): k1(_) , k2(__) , k3(___) , k4(____) {}
	inline void operator += (Tag x){
		(*this) = Tag(
			k1 + x.k1 , max(k1 + x.k2 , k2) ,
			k3 + x.k3 , max(k3 + x.k4 , k4)
		);
	}
}lz[2000005];

struct Seg {
	int a , b , mx2 , cntmx , le; ll s;
	inline Seg(){ a = b = mx2 = -inf; cntmx = le = 0; }
	inline Seg(ll _ , ll __ , ll ___): a(_) , b(__) , s(___) {}
	inline friend Seg operator + (Seg ls , Seg rs){
		Seg ret;
		ret.b = max(ls.b , rs.b);
		ret.s = ls.s + rs.s;
		ret.le = ls.le + rs.le;
		if(ls.a &amp;lt; rs.a){
			ret.a = rs.a; ret.cntmx = rs.cntmx;
			ret.mx2 = max(ls.a , rs.mx2);
		}
		else if(ls.a &amp;gt; rs.a){
			ret.a = ls.a; ret.cntmx = ls.cntmx;
			ret.mx2 = max(ls.mx2 , rs.a);
		}
		else{
			ret.a = ls.a; ret.cntmx = ls.cntmx + rs.cntmx;
			ret.mx2 = max(ls.mx2 , rs.mx2);
		}
		return ret;
	}
	inline void operator += (Tag x){
		b = max(b , a + x.k2); a += x.k1;
		s += 1LL * x.k1 * cntmx + 1LL * x.k3 * (le - cntmx);
		if(mx2 != -inf){
			b = max(b , mx2 + x.k4);
			mx2 += x.k3;
		}
	}
}tr[2000005];

inline void upd(int p , Tag x){ tr[p] += x; lz[p] += x; }

inline void pushdown(int p){
	if(lz[p].k1 == 0 &amp;amp;&amp;amp; lz[p].k2 == 0 &amp;amp;&amp;amp; lz[p].k3 == 0 &amp;amp;&amp;amp; lz[p].k4 == 0) return ;
	int mx = max(tr[p &amp;lt;&amp;lt; 1].a , tr[p &amp;lt;&amp;lt; 1 | 1].a);
	if(tr[p &amp;lt;&amp;lt; 1].a == mx)
		upd(p &amp;lt;&amp;lt; 1 , lz[p]);
	else
		upd(p &amp;lt;&amp;lt; 1 , Tag(lz[p].k3 , lz[p].k4 , lz[p].k3 , lz[p].k4));
	if(tr[p &amp;lt;&amp;lt; 1 | 1].a == mx)
		upd(p &amp;lt;&amp;lt; 1 | 1 , lz[p]);
	else
		upd(p &amp;lt;&amp;lt; 1 | 1 , Tag(lz[p].k3 , lz[p].k4 , lz[p].k3 , lz[p].k4));
	lz[p] = Tag(0 , 0 , 0 , 0);
}

void add(int p , int l , int r , int x , int y , int k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){
		upd(p , Tag(k , k , k , k));
//		printf(&quot;q%d %d %d\n&quot; , l , r , tr[p].a);
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	add(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	add(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

void upd_min(int p , int l , int r , int x , int y , int k){
	if(l &amp;gt; y || r &amp;lt; x || tr[p].a &amp;lt;= k) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y &amp;amp;&amp;amp; k &amp;gt; tr[p].mx2){
		upd(p , Tag(k - tr[p].a , k - tr[p].a , 0 , 0));
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd_min(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd_min(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid ) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) +
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

int a[500005];
void init(int p , int l , int r){
	if(l == r){
		tr[p].a = tr[p].b = tr[p].s = a[l];
		tr[p].cntmx = tr[p].le = 1;
		tr[p].mx2 = -inf;
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

int n , m;

int main(void){
	scanf(&quot;%d%d&quot; , &amp;amp;n , &amp;amp;m);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;a[i]);
	init(1 , 1 , n);
	while(m--){
		int op , l , r; scanf(&quot;%d%d%d&quot; , &amp;amp;op , &amp;amp;l , &amp;amp;r);
		if(op == 1){
			int x; scanf(&quot;%d&quot; , &amp;amp;x);
			add(1 , 1 , n , l , r , x);
		}
		if(op == 2){
			int x; scanf(&quot;%d&quot; , &amp;amp;x);
			upd_min(1 , 1 , n , l , r , x);
		}
		if(op == 3) printf(&quot;%lld\n&quot; , query(1 , 1 , n , l , r).s);
		if(op == 4) printf(&quot;%d\n&quot; , query(1 , 1 , n , l , r).a);
		if(op == 5) printf(&quot;%d\n&quot; , query(1 , 1 , n , l , r).b);
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;CPU监控&lt;/h4&gt;
&lt;p&gt;这题就可以用$ (\max,+) $矩阵。&lt;/p&gt;
&lt;p&gt;很容易想到维护当前最大值$ a $，和历史最大值$ b $。&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}a\b\ \end{bmatrix}\begin{bmatrix}k&amp;amp;k\-\infty&amp;amp;0\ \end{bmatrix}=\begin{bmatrix}a+k\\max{a+k,b}\ \end{bmatrix} $&lt;/p&gt;
&lt;p&gt;如果再加上推平，就需要再多加一个$ 0 $&lt;/p&gt;
&lt;p&gt;$ \begin{bmatrix}a\b\0\ \end{bmatrix}\begin{bmatrix}-\infty&amp;amp;-\infty&amp;amp;-\infty\-\infty&amp;amp;0&amp;amp;-\infty\k&amp;amp;k&amp;amp;0\ \end{bmatrix}=\begin{bmatrix}k\\max{b,k}\0\ \end{bmatrix} $&lt;/p&gt;
&lt;p&gt;不难发现只要第一行第一二个和第三行第一二个会变，于是维护这些，然后跑上面的暴力转移代码即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

const int inf = 2147480000;
int n , m , a[100005];

inline int Add(int x , int y){
	if(x &amp;lt;= -inf || y &amp;lt;= -inf) return -inf;
	return x + y;
}

struct Tag {
	int k11 , k12 , k21 , k22;
	inline Tag(){ k11 = 0; k12 = k21 = k22 = -inf; }
	inline Tag(int _ , int __): k11(_) , k12(_) , k21(__) , k22(__) {}
	inline friend Tag operator + (Tag l , Tag r){
//		if(l.k11 == 0 &amp;amp;&amp;amp; l.k12 == -inf &amp;amp;&amp;amp; l.k21 == -inf &amp;amp;&amp;amp; l.k22 == -inf) return r;
		Tag ret;
		ret.k11 = Add(l.k11 , r.k11);
		ret.k12 = max(l.k12 , Add(l.k11 , r.k12));
		ret.k21 = max(Add(l.k21 , r.k11) , r.k21);
		ret.k22 = max(Add(l.k21 , r.k12) , max(l.k22 , r.k22));
		return ret;
	}
	inline void operator += (Tag x){ (*this) = (*this) + x; }
}lazy[400005];

struct Seg {
	int maxn , ans;
	inline Seg(){ maxn = ans = -inf; }
	inline Seg(int _ , int __): maxn(_) , ans(__) {}
	inline friend Seg operator + (Seg ls , Seg rs){
		return Seg(
			max(ls.maxn , rs.maxn) , 
			max(ls.ans , rs.ans)
		);
	}
	inline void operator += (Tag rs){
		ans = max(ans , max(Add(maxn , rs.k12) , rs.k22));
		maxn = max(Add(maxn , rs.k11) , rs.k21);
		ans = max(ans , maxn);
	}
}tr[400005];

inline void pushdown(int p){
	if(lazy[p].k11 != 0 || lazy[p].k12 != -inf || lazy[p].k21 &amp;gt; -inf || lazy[p].k22 &amp;gt; -inf){
		tr[p &amp;lt;&amp;lt; 1] += lazy[p];
		tr[p &amp;lt;&amp;lt; 1 | 1] += lazy[p];
		lazy[p &amp;lt;&amp;lt; 1] += lazy[p];
		lazy[p &amp;lt;&amp;lt; 1 | 1] += lazy[p];
		lazy[p] = Tag();
	}
} 

void init(int p , int l , int r){
	if(l == r){
		tr[p].maxn = tr[p].ans = a[l];
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

void upd(int p , int l , int r , int x , int y , Tag k){
	if(l &amp;gt; y || r &amp;lt; x) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){ tr[p] += k; lazy[p] += k; return ; }
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) { return tr[p];
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) + 
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

int main(void){
	scanf(&quot;%d&quot; , &amp;amp;n);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;a[i]);
	init(1 , 1 , n);
	scanf(&quot;%d&quot; , &amp;amp;m);
	while(m--){
		char s[5]; scanf(&quot;%s&quot; , s + 1);
		if(s[1] == &apos;Q&apos;){
			int l , r; scanf(&quot;%d%d&quot; , &amp;amp;l , &amp;amp;r);
			printf(&quot;%d\n&quot; , query(1 , 1 , n , l , r).maxn);
		}
		if(s[1] == &apos;A&apos;){
			int l , r; scanf(&quot;%d%d&quot; , &amp;amp;l , &amp;amp;r);
			printf(&quot;%d\n&quot; , query(1 , 1 , n , l , r).ans);
		}
		if(s[1] == &apos;P&apos;){
			int l , r , x; scanf(&quot;%d%d%d&quot; , &amp;amp;l , &amp;amp;r , &amp;amp;x);
			upd(1 , 1 , n , l , r , Tag(x , -inf));
		}
		if(s[1] == &apos;C&apos;){
			int l , r , x; scanf(&quot;%d%d%d&quot; , &amp;amp;l , &amp;amp;r , &amp;amp;x);
			upd(1 , 1 , n , l , r , Tag(-inf , x));
		}
	}
}
/*
5
-5 -3 3 -5 -3 
3
P 1 3 3
C 1 3 5
A 2 4
*/
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;SP1557 GSS2&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;区间最大子段和，相同数贡献仅算一次。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;可以考虑离线，按照 r 排序，然后依次加入。&lt;/p&gt;
&lt;p&gt;每个点维护当前加入 i 的和，于是比较显然，加一个点就相当于$ (pre,i] $的区间加。&lt;/p&gt;
&lt;p&gt;显然答案需要历史最大值，于是只需要实现区间加，区间查历史最大值就做完了。&lt;/p&gt;
&lt;p&gt;由于 SPOJ 我交不了，就没写代码。&lt;/p&gt;
&lt;h2&gt;zkw 线段树&lt;/h2&gt;
&lt;p&gt;这里仅提供模板。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int N;  //区间加，区间和。常数小。
ll qwq[400005] , lazy[400005];
inline void init(){
    N = 1;
    while(N &amp;lt; n + 2) N &amp;lt;&amp;lt;= 2;
    for(int i = 1;i &amp;lt;= n;i++) qwq[i + N] = a[i];
    for(int i = N - 1;i &amp;gt; 0;i--){
        qwq[i] = qwq[i &amp;lt;&amp;lt; 1] + qwq[i &amp;lt;&amp;lt; 1 | 1];
        lazy[i] = 0;
    }
}
inline ll query(int l , int r){
    int L , R , len , ln = 0 , rn = 0;
    ll ret = 0;
    for(L = N + l - 1 , R = N + r + 1 , len = 1;L ^ R ^ 1;L &amp;gt;&amp;gt;= 1 , R &amp;gt;&amp;gt;= 1 , len &amp;lt;&amp;lt;= 1){
        if(lazy[L]) ret += lazy[L] * ln;
        if(lazy[R]) ret += lazy[R] * rn;
        if(~L &amp;amp; 1) ret += qwq[L ^ 1] , ln += len;
        if( R &amp;amp; 1) ret += qwq[R ^ 1] , rn += len;
    }
    for(;L;L &amp;gt;&amp;gt;= 1 , R &amp;gt;&amp;gt;= 1){
        ret += lazy[L] * ln;
        ret += lazy[R] * rn;
    }
    return ret;
}
inline void add(int l , int r , ll x){
    int L , R , len , ln = 0 , rn = 0;
    for(L = N + l - 1 , R = N + r + 1 , len = 1;L ^ R ^ 1;L &amp;gt;&amp;gt;= 1 , R &amp;gt;&amp;gt;= 1 , len &amp;lt;&amp;lt;= 1){
        qwq[L] += x * ln;  qwq[R] += x * rn;
        if(~L &amp;amp; 1) lazy[L ^ 1] += x , qwq[L ^ 1] += x * len , ln += len;
        if( R &amp;amp; 1) lazy[R ^ 1] += x , qwq[R ^ 1] += x * len , rn += len;
    }
    for(;L;L &amp;gt;&amp;gt;= 1 , R &amp;gt;&amp;gt;= 1){
        qwq[L] += x * ln;
        qwq[R] += x * rn;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;选讲&lt;/h2&gt;
&lt;h3&gt;HDU6315（势能线段树）&lt;/h3&gt;
&lt;p&gt;$ a_i=0 $，$ b $为$ n $的排列。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$ a $区间加。&lt;/li&gt;
&lt;li&gt;求区间$ \sum \lfloor a_i/b_i \rfloor $。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ n,m\le 10^5 $&lt;/p&gt;
&lt;p&gt;注意到答案最大为 $ n/1+...n/n $，大约是1e6，于是维护每个数还要加几次才会更新答案，如果区间最小为 $ 1 $，则$ log n $找到这个点，改答案，总时间复杂度为$ O(n\log^2 n) $&lt;/p&gt;
&lt;h3&gt;Ynoi P5354 由乃的OJ&lt;/h3&gt;
&lt;p&gt;&amp;lt;!-- 这是一张图片，ocr 内容为： --&amp;gt;
&lt;img src=&quot;https://cdn.nlark.com/yuque/0/2025/png/34441004/1745805224608-5c3a7080-ec58-40d3-be87-1e3e2f165242.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;比较显然，先树剖转链。&lt;/p&gt;
&lt;p&gt;然后可以建$ 64 $棵线段树，然后每颗树维护这段区间传入$ 0/1 $出来的值，然后贪心地选$ 1 $即可。$ O(mk\log n) $很可惜过不了。&lt;/p&gt;
&lt;p&gt;其实因为运算符一样，可以一起计算：线段树维护传如$ 000.../1111... $出来的值，然后考虑如何合并左右子树。&lt;/p&gt;
&lt;p&gt;这样即可：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;tr[p][0] = ((tr[p &amp;lt;&amp;lt; 1 | 1][0] &amp;amp; (~tr[p &amp;lt;&amp;lt; 1][0])) | (tr[p &amp;lt;&amp;lt; 1 | 1][1] &amp;amp; tr[p &amp;lt;&amp;lt; 1][0]));
tr[p][1] = ((tr[p &amp;lt;&amp;lt; 1 | 1][0] &amp;amp; (~tr[p &amp;lt;&amp;lt; 1][1])) | (tr[p &amp;lt;&amp;lt; 1 | 1][1] &amp;amp; tr[p &amp;lt;&amp;lt; 1][1]));	
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;。。。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;algorithm&amp;gt;
#include &amp;lt;vector&amp;gt;
using namespace std;
typedef unsigned long long ll;

int n , m , k; pair &amp;lt;int , ll&amp;gt; a[100005];
vector &amp;lt;int&amp;gt; g[100005];

int dep[100005] , son[100005] , fa[100005] , siz[100005];
void dfs1(int x , int f , int d){
	siz[x] = 1; fa[x] = f; dep[x] = d;
	int maxn = -1;
	for(int nxt : g[x]){
		if(nxt == f) continue;
		dfs1(nxt , x , d + 1);
		siz[x] += siz[nxt];
		if(siz[nxt] &amp;gt; maxn){
			maxn = siz[nxt];
			son[x] = nxt;
		}
	}
}

int tp[100005] , id[100005] , cnt; pair &amp;lt;int , ll&amp;gt; w[100005];
void dfs2(int x , int top){
	tp[x] = top;
	w[id[x] = ++cnt] = a[x];
	if(son[x]) dfs2(son[x] , top);
	for(int nxt : g[x]){
		if(nxt == fa[x] || nxt == son[x]) continue;
		dfs2(nxt , nxt);
	}
}

ll tr[400005][4];

inline void pushup(int p){
	tr[p][0] = ((tr[p &amp;lt;&amp;lt; 1 | 1][0] &amp;amp; (~tr[p &amp;lt;&amp;lt; 1][0])) | (tr[p &amp;lt;&amp;lt; 1 | 1][1] &amp;amp; tr[p &amp;lt;&amp;lt; 1][0]));
	tr[p][1] = ((tr[p &amp;lt;&amp;lt; 1 | 1][0] &amp;amp; (~tr[p &amp;lt;&amp;lt; 1][1])) | (tr[p &amp;lt;&amp;lt; 1 | 1][1] &amp;amp; tr[p &amp;lt;&amp;lt; 1][1]));	
	tr[p][2] = ((tr[p &amp;lt;&amp;lt; 1][2] &amp;amp; (~tr[p &amp;lt;&amp;lt; 1 | 1][2])) | (tr[p &amp;lt;&amp;lt; 1][3] &amp;amp; tr[p &amp;lt;&amp;lt; 1 | 1][2]));
	tr[p][3] = ((tr[p &amp;lt;&amp;lt; 1][2] &amp;amp; (~tr[p &amp;lt;&amp;lt; 1 | 1][3])) | (tr[p &amp;lt;&amp;lt; 1][3] &amp;amp; tr[p &amp;lt;&amp;lt; 1 | 1][3]));	
}

inline pair &amp;lt;ll , ll&amp;gt; merge(pair &amp;lt;ll , ll&amp;gt; ls , pair &amp;lt;ll , ll&amp;gt; rs , bool t = 0){
	pair &amp;lt;ll , ll&amp;gt; ret;
	if(t) swap(ls , rs);
	ret.first  = ((rs.first &amp;amp; (~ls.first )) | (rs.second &amp;amp; ls.first ));
	ret.second = ((rs.first &amp;amp; (~ls.second)) | (rs.second &amp;amp; ls.second));
	return ret;
}

void init(int p , int l , int r){
	if(l == r){
		tr[p][0] = 0; tr[p][1] = ~(ll)0;
		if(w[l].first == 1) tr[p][0] &amp;amp;= w[l].second , tr[p][1] &amp;amp;= w[l].second;
		if(w[l].first == 2) tr[p][0] |= w[l].second , tr[p][1] |= w[l].second;
		if(w[l].first == 3) tr[p][0] ^= w[l].second , tr[p][1] ^= w[l].second;
		tr[p][2] = tr[p][0]; tr[p][3] = tr[p][1];
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid);
	init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	pushup(p);
}

void upd(int p , int l , int r , int x , pair &amp;lt;int , ll&amp;gt; y){
	if(l &amp;gt; x || r &amp;lt; x) return ;
	if(l == r){
		tr[p][0] = 0; tr[p][1] = ~(ll)0;
		if(y.first == 1) tr[p][0] &amp;amp;= y.second , tr[p][1] &amp;amp;= y.second;
		if(y.first == 2) tr[p][0] |= y.second , tr[p][1] |= y.second;
		if(y.first == 3) tr[p][0] ^= y.second , tr[p][1] ^= y.second;
		tr[p][2] = tr[p][0]; tr[p][3] = tr[p][1];
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	pushup(p);
}

pair &amp;lt;ll , ll&amp;gt; query(int p , int l , int r , int x , int y,  int k = 0){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return {tr[p][k] , tr[p][1 + k]};
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	if(x &amp;gt;  mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	return merge(
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k) ,
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k) ,
		(k &amp;gt; 0)
	);
}

inline pair &amp;lt;ll , ll&amp;gt; getans(int x , int y){
	pair &amp;lt;ll , ll&amp;gt; ret1 , ret2 , ret3;
	bool f1 = 1 , f2 = 1;
	while(tp[x] != tp[y]){
		if(dep[tp[x]] &amp;gt;= dep[tp[y]]){
			if(f1) ret1 = query(1 , 1 , n , id[tp[x]] , id[x] , 2) , f1 = 0;
			else ret1 = merge(ret1 , query(1 , 1 , n , id[tp[x]] , id[x] , 2));
			x = fa[tp[x]];
		}
		else{
			if(f2) ret2 = query(1 , 1 , n , id[tp[y]] , id[y]) , f2 = 0;
			else ret2 = merge(query(1 , 1 , n , id[tp[y]] , id[y]) , ret2);
			y = fa[tp[y]];
		}
	}
	if(dep[x] &amp;lt; dep[y]) ret3 = query(1 , 1 , n , id[x] , id[y]);
	else ret3 = query(1 , 1 , n , id[y] , id[x] , 2);
	if(f1 &amp;amp;&amp;amp; f2) return ret3;
	if(f1) return merge(ret3 , ret2);
	if(f2) return merge(ret1 , ret3);
	return merge(merge(ret1 , ret3) , ret2);
}

int main(void){
	scanf(&quot;%d%d%d&quot; , &amp;amp;n , &amp;amp;m , &amp;amp;k);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d%llu&quot; , &amp;amp;a[i].first , &amp;amp;a[i].second);
	for(int i = 1 , u , v;i &amp;lt; n;i++){
		scanf(&quot;%d%d&quot; , &amp;amp;u , &amp;amp;v);
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs1(1 , 0 , 1); dfs2(1 , 1);
	init(1 , 1 , n);
	while(m--){
		int op , x , y; ll z;
		scanf(&quot;%d%d%d%llu&quot; , &amp;amp;op , &amp;amp;x , &amp;amp;y , &amp;amp;z);
		if(op == 1){
			pair &amp;lt;ll , ll&amp;gt; ret = getans(x , y);
			ll ans = 0 , nw = 0;
			for(int i = k - 1;i &amp;gt;= 0;i--){
				bool a0 = (ret.first  &amp;gt;&amp;gt; i &amp;amp; 1ull);
				bool a1 = (ret.second &amp;gt;&amp;gt; i &amp;amp; 1ull);
				if(a0) ans |= ((ll)1 &amp;lt;&amp;lt; i);
				else if(a1 &amp;amp;&amp;amp; (nw | ((ll)1 &amp;lt;&amp;lt; i)) &amp;lt;= z){
					ans |= ((ll)1 &amp;lt;&amp;lt; i);
					nw |= ((ll)1 &amp;lt;&amp;lt; i);
				}
			}
			printf(&quot;%llu\n&quot; , ans);
		}
		if(op == 2)
			upd(1 , 1 , n , id[x] , {y , z});
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;P11334&lt;/h3&gt;
&lt;p&gt;&amp;lt;font style=&quot;color:rgb(64, 64, 64);&quot;&amp;gt;显然可以线段树，因为是可合并信息。&amp;lt;/font&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;font style=&quot;color:rgb(64, 64, 64);&quot;&amp;gt;考虑每段区间维护最长等差数列长度，于是为了合并它，就需要再维护区间前缀最长等差数列长度，和后缀最长。而且合并时也需要判断是否能合并，所以还需要维护前缀等差数列和后缀等差数列的首尾项。（可以类比线段树维护最大子段和）&amp;lt;/font&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;font style=&quot;color:rgb(64, 64, 64);&quot;&amp;gt;综上，需要维护五个值，区间内的答案，区间前缀最大，后缀最大，前缀等差数列，后缀等差数列。&amp;lt;/font&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;font style=&quot;color:rgb(64, 64, 64);&quot;&amp;gt;代码特别难写。。考虑情况特别多。&amp;lt;/font&amp;gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;long long 没开全，1打成2，推平应先下放，merge情况考虑少了，洛谷评测太慢了。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;P9631&lt;/h3&gt;
&lt;p&gt;一操作简单区间取最值不说，重点在二操作，有个结论，我不会证，，，就是这种游戏下，如果异或和为 0 则先手必输。&lt;/p&gt;
&lt;p&gt;于是可以先维护区间异或和，然后尽量让第二步的人的异或和为 0，这样就是必胜的了。&lt;/p&gt;
&lt;p&gt;因为是拿，于是要满足$ a_i\oplus x \le a_i $的才可以拿，算这玩意有几个即可。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;cstring&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

int lz[800005];

struct Seg {
	int mi , cntmi , mi2 , ans;
	int tot[31];
	inline Seg(){ memset(tot , 0 , sizeof(tot)); }
	inline friend Seg operator + (Seg ls , Seg rs){
		Seg ret;
		ret.ans = (ls.ans ^ rs.ans);
		if(ls.mi &amp;lt; rs.mi){
			ret.mi = ls.mi; ret.cntmi = ls.cntmi;
			ret.mi2 = min(ls.mi2 , rs.mi);
		}
		else if(ls.mi &amp;gt; rs.mi){
			ret.mi = rs.mi; ret.cntmi = rs.cntmi;
			ret.mi2 = min(ls.mi , rs.mi2);
		}
		else{
			ret.mi = ls.mi; ret.cntmi = ls.cntmi + rs.cntmi;
			ret.mi2 = min(ls.mi2 , rs.mi2);
		}
		for(int i = 0;i &amp;lt;= 30;i++) ret.tot[i] = ls.tot[i] + rs.tot[i];
		return ret;
	}
	inline void operator += (int x){
		if(cntmi &amp;amp; 1) ans ^= mi ^ x;
		for(int i = 0;i &amp;lt;= 30;i++) if(mi &amp;gt;&amp;gt; i &amp;amp; 1)
			tot[i] -= cntmi;
		mi = x;
		for(int i = 0;i &amp;lt;= 30;i++) if(mi &amp;gt;&amp;gt; i &amp;amp; 1)
			tot[i] += cntmi;
	}
}tr[800005]; 

inline void upd(int p , int x){ tr[p] += x; lz[p] = x; }

inline void pushdown(int p){
	if(!lz[p]) return ;
	int mi = min(tr[p &amp;lt;&amp;lt; 1].mi , tr[p &amp;lt;&amp;lt; 1 | 1].mi);
	if(tr[p &amp;lt;&amp;lt; 1].mi == mi) upd(p &amp;lt;&amp;lt; 1 , lz[p]);
	if(tr[p &amp;lt;&amp;lt; 1 | 1].mi == mi) upd(p &amp;lt;&amp;lt; 1 | 1 , lz[p]);
	lz[p] = 0;
}

void upd_max(int p , int l , int r , int x , int y , int k){
	if(l &amp;gt; y || r &amp;lt; x || tr[p].mi &amp;gt;= k) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y &amp;amp;&amp;amp; tr[p].mi2 &amp;gt; k){
		upd(p , k);
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	upd_max(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd_max(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

Seg query(int p , int l , int r , int x , int y){
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y) return tr[p];
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	pushdown(p);
	if(y &amp;lt;= mid) return query(p &amp;lt;&amp;lt; 1 , l , mid , x , y);
	if(x &amp;gt; mid) return query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y);
	return (
		query(p &amp;lt;&amp;lt; 1 , l , mid , x , y) + 
		query(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y)
	);
}

int a[200005];
void init(int p , int l , int r){
	if(l == r){
		tr[p].mi = tr[p].ans = a[l];
		tr[p].cntmi = 1; tr[p].mi2 = (1 &amp;lt;&amp;lt; 30);
		for(int i = 0;i &amp;lt;= 30;i++) if(a[l] &amp;gt;&amp;gt; i &amp;amp; 1)
			tr[p].tot[i]++;
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	init(p &amp;lt;&amp;lt; 1 , l , mid); init(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r);
	tr[p] = tr[p &amp;lt;&amp;lt; 1] + tr[p &amp;lt;&amp;lt; 1 | 1];
}

int n , q;

int main(void){
	scanf(&quot;%d%d&quot; , &amp;amp;n , &amp;amp;q);
	for(int i = 1;i &amp;lt;= n;i++) scanf(&quot;%d&quot; , &amp;amp;a[i]);
	init(1 , 1 , n);
	while(q--){
		int op , l , r , x;
		scanf(&quot;%d%d%d%d&quot; , &amp;amp;op , &amp;amp;l , &amp;amp;r , &amp;amp;x);
		if(op == 1) upd_max(1 , 1 , n , l , r , x);
		if(op == 2){
			Seg ans = query(1 , 1 , n , l , r);
			ans.ans ^= x;
//			printf(&quot;w%d\n&quot; , ans.ans);
			int t = -1;
			for(int i = 30;i &amp;gt;= 0;i--) if(ans.ans &amp;gt;&amp;gt; i &amp;amp; 1){ t = i; break; }
			if(t == -1) puts(&quot;0&quot;);
			else printf(&quot;%d\n&quot; , ans.tot[t] + (x &amp;gt;&amp;gt; t &amp;amp; 1));
		}
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;P5524 Ynoi 2012  NOIP2015充满了希望&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;交换&lt;/li&gt;
&lt;li&gt;推平&lt;/li&gt;
&lt;li&gt;查询&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;给你操作，问顺序执行$ [l,r] $的操作后所有查询操作的和。&lt;/p&gt;
&lt;p&gt;$ n,m,q\le 10^6 $。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我们用线段树记录每个点最后一次执行的二操作的序号。&lt;/p&gt;
&lt;p&gt;对于一操作，也是交换。&lt;/p&gt;
&lt;p&gt;对于二操作，还是区间推平。&lt;/p&gt;
&lt;p&gt;对于三操作，贡献即为$ v_{t_i} $。&lt;/p&gt;
&lt;p&gt;那么将询问离线。枚举$ r $，维护$ s_i $表示$ [i,r] $之间的答案，移动方法如上，需要单点查询，区间加，可以用树状数组。于是做完了。&lt;/p&gt;
&lt;p&gt;代码还没写。&lt;/p&gt;
&lt;h1&gt;扫描线&lt;/h1&gt;
&lt;p&gt;参考：&lt;a href=&quot;https://www.luogu.com.cn/article/9vwv8pe7&quot;&gt;https://www.luogu.com.cn/article/9vwv8pe7&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;答案贡献类&lt;/h2&gt;
&lt;p&gt;可以考虑每个点要区间满足什么要求使得这个点可以对答案做贡献&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;常用技巧：&lt;/p&gt;
&lt;p&gt;lxl《树套堆》&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;区间取min，撤销第 i 次操作，求单点值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如题，树套堆。线段树每个节点维护一个堆，然后标记永久化。&lt;/p&gt;
&lt;p&gt;$ O(\log^2 n) $&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;queue&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;

const int inf = 1e9;

struct Zbojin_Queue {
	priority_queue &amp;lt;int , vector &amp;lt;int&amp;gt; , greater &amp;lt;int&amp;gt; &amp;gt; q , death;
	inline void push(int x){ q.push(x); }
	inline void erase(int x){ death.push(x); }
	inline int top(){
		while(!death.empty() &amp;amp;&amp;amp; q.top() == death.top())
			q.pop() , death.pop();
		return q.empty()? inf : q.top();
	}
}qwq[2000005];

void upd(int p , int l , int r , int x , int y , int k){
	if(r &amp;lt; x || l &amp;gt; y) return ;
	if(l &amp;gt;= x &amp;amp;&amp;amp; r &amp;lt;= y){
		if(k &amp;gt; 0) qwq[p].push(k);
		else    qwq[p].erase(-k);
		return ;
	}
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	upd(p &amp;lt;&amp;lt; 1 , l , mid , x , y , k);
	upd(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x , y , k);
}

int getmin(int p , int l , int r , int x){
	if(l &amp;gt; x || r &amp;lt; x) return inf;
	int ret = qwq[p].top();
	if(l == r) return ret;
	int mid = (l + r) &amp;gt;&amp;gt; 1;
	return min(ret , min(
		getmin(p &amp;lt;&amp;lt; 1 , l , mid , x) , 
		getmin(p &amp;lt;&amp;lt; 1 | 1 , mid + 1 , r , x)
	));
} 

int main(void){
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个方法也可以用在：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;区间推平，区间撤销推平&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;只需要把值变成 pair，第一个值是操作时间，第二个是推平的值。&lt;/p&gt;
&lt;p&gt;然后因为是pair，所以堆（大根堆）顶的值一定是时间最大的，也就是最近推平的。删除同理。&lt;/p&gt;
&lt;p&gt;其实因为插入是按时间顺序的，因此可以用栈来代替。时间复杂度少个log。&lt;/p&gt;
&lt;p&gt;如果用栈，建议用手写的，由于不知名原因，用STL的stack空间太大了。。。。&lt;/p&gt;
&lt;h3&gt;例题&lt;/h3&gt;
&lt;h4&gt;CF522D Closest Equals&lt;/h4&gt;
&lt;p&gt;注意到，显然只有最近的两个相同的点才能对答案做贡献，并且答案区间要包含这两个点，即 $ l\le i, j \le r $，用上面的树套堆维护扫描线即可。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://codeforces.com/problemset/submission/522/315930292&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;CF1000F One Occurrence&lt;/h4&gt;
&lt;p&gt;记$ pre_i,nxt_i $，为$ i $前一个相同和后一个相同的。假如要点$ x $有贡献，那么区间必须满足$ l&amp;gt;pre_x,r&amp;lt;nxt_x $，扫描线维护即可。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://codeforces.com/problemset/submission/1000/315932594&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;CF453E Little Pony and Lord Tirek(-10)&lt;/h4&gt;
&lt;p&gt;假如$ a_i $均为$ 0 $，可以算出这个点最小需要几时才能到最大值，记为$ f_i $，那么容易想到用珂朵莉树维护&lt;strong&gt;修改的时间&lt;/strong&gt;，于是就有多个连续块。&lt;/p&gt;
&lt;p&gt;令$ t $为每个块的时间差，然后每个点分两种情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$ t&amp;gt;f_i $：这个点为$ m_i $。&lt;/li&gt;
&lt;li&gt;$ t \le f_i $：这个点为 $ tr_i $。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以预先把每个点放到两个二维平面上，$ x $轴代表$ i $，$ y $轴代表$ f $，坐标则为$ (i,f_i) $，权值为$ m_i $或$ r_i $。&lt;/p&gt;
&lt;p&gt;那么每次询问相当于求第一个二维平面$ [l,t+1,r,MAX] $矩形的和，加上第二个二维平面$ [l,1,r,t] $矩形的和。于是离线下来扫描线，扫描线可以用树状数组比较快。&lt;/p&gt;
&lt;p&gt;然后是$ a_i\not = 0 $时，只需要在第一次修改时暴力处理，由于修改一次后都为$ 0 $，所以时间复杂度不会增加。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-1：没写完，交一发看看。&lt;/li&gt;
&lt;li&gt;-2：调RE的问题，树状数组$ 0 $的会RE。。&lt;/li&gt;
&lt;li&gt;-3~-6：加$ a_i\not =0 $的情况，调。&lt;/li&gt;
&lt;li&gt;-7&amp;amp;-8：数组开小。&lt;/li&gt;
&lt;li&gt;-9&amp;amp;-10：long long&amp;amp;快读。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://codeforces.com/problemset/submission/453/316031253&quot;&gt;code&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/xr5nux3z&quot;&gt;题解&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;时间扫描类&lt;/h2&gt;
&lt;p&gt;常用技巧：时光倒流。&lt;/p&gt;
&lt;h3&gt;例题&lt;/h3&gt;
&lt;h4&gt;P3863 序列&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;区间加，求 i 点之前有几个时刻的值大于 y&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;实现以时间和下标建系，修改是区间加，查询是区间排名，分块。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;cstdio&amp;gt;
#include &amp;lt;vector&amp;gt;
#include &amp;lt;algorithm&amp;gt;
using namespace std;
typedef long long ll;

int n , m; ll a[100005];

char buf[1 &amp;lt;&amp;lt; 21] , *p1 , *p2;
#define GC p1 == p2 &amp;amp;&amp;amp; (p2 = (p1 = buf) + fread(buf , 1 , 1 &amp;lt;&amp;lt; 21 , stdin) , p1 == p2) ? EOF : *p1++
inline int read() {
	int x = 0;
    bool f = false;
	char ch = GC;
	while(ch &amp;gt; &apos;9&apos; || ch &amp;lt; &apos;0&apos;){
        if(ch == &apos;-&apos;)
            f = true;
        ch = GC;
    }
	while(ch &amp;gt;= &apos;0&apos; &amp;amp;&amp;amp; ch &amp;lt;= &apos;9&apos;){
		x = (x &amp;lt;&amp;lt; 1) + (x &amp;lt;&amp;lt; 3) + (ch ^ 48);
		ch = GC;
	}
	return f? -x : x; 
}

namespace LOVE {
	const int kuai = 220;
	int L[(100005 / kuai) + 5] , R[(100005 / kuai) + 5] , id[100005];
	ll b[100005] , lz[(100005 / kuai) + 5];
	
	inline void add(int l , int r , int x){
		const int st = id[l] , ed = id[r];
		if(st == ed){
			for(int i = l;i &amp;lt;= r;i++) a[i] += x;
			for(int i = L[st];i &amp;lt;= R[st];i++) b[i] = a[i];
			sort(b + L[st] , b + R[st] + 1);
			return ;
		}
		for(int i = l;i &amp;lt;= R[st];i++) a[i] += x;
		for(int i = L[st];i &amp;lt;= R[st];i++) b[i] = a[i];
		sort(b + L[st] , b + R[st] + 1);
		for(int i = st + 1;i &amp;lt; ed;i++) lz[i] += x;
		for(int i = L[ed];i &amp;lt;= r;i++) a[i] += x;
		for(int i = L[ed];i &amp;lt;= R[ed];i++) b[i] = a[i];
		sort(b + L[ed] , b + R[ed] + 1);
	}
	
	inline int query(int l , int r , ll x){
		const int st = id[l] , ed = id[r];
		int ret = 0;
		if(st == ed){
			for(int i = l;i &amp;lt;= r;i++) ret += (a[i] + lz[st] &amp;gt;= x);
			return ret;
		}
		for(int i = l;i &amp;lt;= R[st];i++) ret += (a[i] + lz[st] &amp;gt;= x);
		for(int i = st + 1;i &amp;lt; ed;i++)
			ret += (R[i] + b + 1 - lower_bound(b + L[i] , b + R[i] + 1 , x - lz[i]));
		for(int i = L[ed];i &amp;lt;= r;i++) ret += (a[i] + lz[ed] &amp;gt;= x);
		return ret;
	}
	
	inline void init(){
		const int N = m / kuai + 1;
		for(int i = 1;i &amp;lt;= N;i++){
			L[i] = R[i - 1] + 1;
			R[i] = min(R[i - 1] + kuai , m + 1);
			for(int j = L[i];j &amp;lt;= R[i];j++) id[j] = i;
		}
	}
}

struct QWQ { int l , r , k , id; };
vector &amp;lt;QWQ&amp;gt; u[100005] , q[100005];
int ans[100005];

int main(void){
	n = read(); m = read();
	for(int i = 1 , x , lt = 0;i &amp;lt;= n;i++){
		x = read();
		u[i].push_back((QWQ){0 , m , x - lt , 0});
		lt = x;
	}
	LOVE::init();
	int nw = 0;
	for(int i = 1;i &amp;lt;= m;i++){
		int op , l , r; op = read(); l = read(); r = read();
		if(op == 1){
			int x; x = read();
			u[l].push_back((QWQ){i , m , x , 0});
			u[r + 1].push_back((QWQ){i , m , -x , 0});
		}
		if(op == 2){
			q[l].push_back((QWQ){0 , i - 1 , r , ++nw});
		}
	}
	for(int i = 0;i &amp;lt;= n;i++){
		for(QWQ j : u[i]) LOVE::add(j.l + 1 , j.r + 1 , j.k);
		for(QWQ j : q[i]) ans[j.id] = LOVE::query(j.l + 1 , j.r + 1 , j.k);
	}
	for(int i = 1;i &amp;lt;= nw;i++) printf(&quot;%d\n&quot; , ans[i]);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;致谢&amp;amp;参考文献&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/9vwv8pe7&quot;&gt;浅谈扫描线 Larry76&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;论文《区间最值操作与历史最值问题》——吉如一&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.com.cn/article/rfalvjih&quot;&gt;区间最值操作与区间历史最值详解 灵梦&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.luogu.me/article/rqmfqvmu&quot;&gt;https://www.luogu.me/article/rqmfqvmu&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/Meatherm/p/17925813.html#:~:text=%E5%A6%82%E6%9E%9C%E6%89%80%E6%9C%89%E4%BF%A1%E6%81%AF%E9%83%BD%E5%8F%AF%E4%BB%A5%E8%A2%AB%E8%A1%A8%E7%A4%BA%E4%B8%BA%E8%A1%8C%E6%95%B0%E7%9B%B8%E5%90%8C%E7%9A%84%E5%88%97%E5%90%91%E9%87%8F%20x%20x%EF%BC%8C%E5%90%88%E5%B9%B6%E4%BF%A1%E6%81%AF%E5%8F%AF%E4%BB%A5%E8%A1%A8%E7%A4%BA%E4%B8%BA%E5%90%91%E9%87%8F%E5%8A%A0%E6%B3%95%EF%BC%8C%E4%B8%80%E4%B8%AA%E6%A0%87%E8%AE%B0%E4%BD%9C%E7%94%A8%E5%9C%A8%E4%BF%A1%E6%81%AF%E4%B8%8A%E5%8F%AF%E4%BB%A5%E7%94%A8%E7%9F%A9%E9%98%B5%20A%20A,%E6%9D%A5%E6%8F%8F%E8%BF%B0%EF%BC%8C%E9%82%A3%E4%B9%88%E8%BF%99%E7%A7%8D%E6%A0%87%E8%AE%B0%20%2F%20%E4%BF%A1%E6%81%AF%E5%BD%A2%E5%BC%8F%E5%B0%B1%E6%98%AF%E4%B8%80%E4%B8%AA%E5%8F%8C%E5%8D%8A%E7%BE%A4%E6%A8%A1%E5%9E%8B%EF%BC%9A%E8%A1%8C%E6%95%B0%E7%9B%B8%E5%90%8C%E7%9A%84%E5%88%97%E5%90%91%E9%87%8F%E5%AF%B9%E5%8A%A0%E6%B3%95%E6%9E%84%E6%88%90%E4%BA%A4%E6%8D%A2%E7%BE%A4%EF%BC%8C%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95%E6%BB%A1%E8%B6%B3%E7%BB%93%E5%90%88%E5%BE%8B%E4%B8%94%E5%AD%98%E5%9C%A8%E5%8D%95%E4%BD%8D%E7%9F%A9%E9%98%B5%20I%20I%EF%BC%8C%E5%B9%B6%E4%B8%94%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95%E5%AF%B9%E7%9F%A9%E9%98%B5%E5%8A%A0%E6%B3%95%E4%B9%9F%E6%98%AF%E5%A4%A9%E7%84%B6%E6%BB%A1%E8%B6%B3%E5%88%86%E9%85%8D%E5%BE%8B%E7%9A%84%E3%80%82%20%E5%B8%B8%E8%A7%81%E7%9A%84%E7%9F%A9%E9%98%B5%E6%9C%89%E4%B8%A4%E7%A7%8D%E3%80%82&quot;&gt;https://www.cnblogs.com/Meatherm/p/17925813.html#:~&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;lxl 的课件。&lt;/p&gt;
&lt;p&gt;oi-wki 等&lt;/p&gt;
&lt;p&gt;感谢 fen sir 对我线段树标题的评论&lt;/p&gt;
&lt;p&gt;感谢冯某对我NOIP 2022 比赛解答。&lt;/p&gt;
&lt;p&gt;感谢线段树对本文的大力支持。&lt;/p&gt;
</content:encoded></item></channel></rss>