2024.10.23 鲜花

恋ひ恋ふ縁
诚、意地の悪い神の所业か?
奇迹?縁?袂触合う不思议
花ひとひら揺れて
不意に宿ってた
うなじ解いてく春风
戯れはそこそこに
恋手ほどきしてくだしゃんせ
汤気にほんのり頬染て
夜风に愿ふ
…いざ!!蝶と舞ひ花となりて
衣を乱して祓いましょう
あやなしココロの秽れ
…故!!刀となり楯となりて
この想ひ护り赐え
君が恋の门を杀めた
恋の罠は密やかに仕挂けなきゃ
次の一手すけすけだから困る
锻錬じゃどうにもなんない
揺れる心模様
どっちが先だ?恋烦ひ
覚悟してとおりゃんせ
夜道と乙女にご用心
汤気の香り漂わせ诱う夜宴
…実に!本日はデェト日和
しどけなく诱いましょ?
凭きませ偲ぶ恋梦…
故!静となり动となりて
我を导き赐え
君の剣がハァトを射抜いた
…いざ!!蝶と舞ひ花となりて
衣を乱して祓いましょう
前世から繋がる运命
…故!刀となり花と生きて
この爱护り赐え
君はもう縁に选ばれた

基础数据结构进阶

  1. 平衡树合并:

    其实是非常简单的,就是每次钦定堆值大(也可以是小,看自己的排序方式)的作为根,用其键值切(就是 split)另一个树,分别和左右子树递归即可。

    void frg(int a,int b,int &t){
    	if(!a||!b) return t=a|b,void();
    	if(rd[a]>rd[b]) swap(a,b);
    	t=a,spl(a,b,b,vl[a]);
    	frg(lson,a,lson),frg(rson,b,rson);
    	Upd(t);
    }
    

    复杂度分析可以参考 this,大概是在加、减、除、根号时是单 \(\log\),取模是双 \(\log\)

    但是拿这个做线段树合并是 \(log^2\) 的,具体的,考虑一次合并 \(k\) 段相交值域是 \(k\log n\) 级别的,显然可以构造一棵完全二叉树满足一共有 \(n\log n\) 段值域,让每一层都有 \(n\) 的贡献,就是形如 \(1,3,5\)\(2,4,6\) 这样的。

  2. 线段树双半群:

    众所周知,线段树可以维护半群。

    主要维护两个群 \(I,T\) 分别表示信息和标记,考虑三个方面,\(I+I\)\(I+T\)\(T+T\)

    一般的 \(I+I\)\(I+T\) 比较好做,主要是 \(T+T\),可以一直新加标记尝试维护,但很麻烦。

    有简单点的做法,考虑矩阵,矩阵天然满足结合律,但是有个比较大的常数。

    可以将矩阵拆开,只维护有用的位置,这样就和标记一样了。

  3. 兔队线段树:

    用来维护两个 \(\min/\max\) 套起来的问题,一般里面的是前后缀,可以带修。

    经典引入是 P4198 楼房重建

    现求斜率并离散化,问题变为求 \(\sum\limits_{i=1}^n[s_i>\max_{j=1}^{i-1}\{s_j\}]\)

    考虑在 \(l,r\) 上维护最大值 \(max\)只考虑本区间,即不考虑 \([1,l)\) 的贡献的和 \(cnt\)

    考虑合并,发现 \((min,r]\) 只会被 \(\max_{i=l}^{mid}{s_i}\) 影响,于是用 \(calc(i,pre)\) 表示受 \(pre\) 影响后 \(i\) 子树内的贡献。

    引用小粉兔的伪代码。

    \[\displaystyle \begin{array}{l} \textbf{def: } \mathrm{calc}(i, pre) \\ \qquad \textbf{if } (i \text{ is a leaf node}) \\ \qquad \qquad \textbf{return } {\color{green}{[\max[i] > pre]}} \\ \qquad \textbf{else} \\ \qquad \qquad \textbf{if } (\max[\mathrm{leftchild}[i]] > pre) \\ \qquad \qquad \qquad \textbf{return } {\color{blue}{\mathrm{calc}(\mathrm{leftchild}[i], pre)}} + {\color{red}{(\mathrm{cnt}[i] - \mathrm{cnt}[\mathrm{leftchild}[i]])}} \\ \qquad \qquad \textbf{else} \\ \qquad \qquad \qquad \textbf{return } {\color{blue}{0}} + {\color{red}{\mathrm{calc}(\mathrm{rightchild}[i], pre)}} \\ \qquad \qquad \textbf{endif.} \\ \qquad \textbf{endif.} \\ \textbf{enddef.} \end{array} \]

    蓝色是左子树,红色是右子树。

    容易发现在统计贡献时用到了差分,考虑不用可差分性。

    更改节点维护信息,在 \(l,r\) 上只维护右子树的贡献,\(calc\)意义不变

    \[\displaystyle \begin{array}{l} \textbf{def: } \mathrm{calc}(i, pre) \\ \qquad \textbf{if } (i \text{ is a leaf node}) \\ \qquad \qquad \textbf{return } {\color{green}{[\max[i] > pre]}} \\ \qquad \textbf{else} \\ \qquad \qquad \textbf{if } (\max[\mathrm{leftchild}[i]] > pre) \\ \qquad \qquad \qquad \textbf{return } {\color{blue}{\mathrm{calc}(\mathrm{leftchild}[i], pre)}} + {\color{red}{\mathrm{cnt}[i]}} \\ \qquad \qquad \textbf{else} \\ \qquad \qquad \qquad \textbf{return } {\color{blue}{0}} + {\color{red}{\mathrm{calc}(\mathrm{rightchild}[i], pre)}} \\ \qquad \qquad \textbf{endif.} \\ \qquad \textbf{endif.} \\ \textbf{enddef.} \end{array} \]

    查询时调用 \(calc\) 即可。

    例题:P7230 [COCI2015-2016#3] NEKAMELEONI

    首先发现,对于一个右端点,其左端点一定是右端点以后的数的 \(pre\) 的最小值,设 \(A_i=pre_{i+1}\),若不存在就设为 \(-n\),于是问题就变成了求 \(\min_{i=1}^n\{i-min_{j=i}^n\{A_j\}+1\}\)

    直接套兔队线段树即可。

P


posted @ 2024-10-23 10:32  xrlong  阅读(72)  评论(6编辑  收藏  举报