做题实录
新的一年要自律。
1.13 终于放假了,这以后每天得 5 道题吧。
1.1
P5459:记前缀和,枚举右端点 \(r\),易知 \(s_l\in[s_r-R,s_r-L],l\in [0,r)\),离散化后树状数组,或直接动态开点线段树解决问题。
P6492:类似线段树维护最大子段和,记录每个区间的左右端点,最大答案,以左端点为开始的最大答案,以右端点为结束的最大答案,然后改改 pushup 即可。
P1438:区间等差数列加板题,用线段树维护差分数组,那么操作就变为 \(d_l\) 加首项,\(d_{l+1...r}\) 加公差,\(d_{r+1}\) 减末项。
P1471:就推方差式子,最后只跟区间和以及区间平方和有关,线段树维护。
CF291E:作业题,其实是要写 dsu 的,但是是个 kmp 傻逼题,就直接边 dfs 边做 kmp,比 dsu 代码短 1kb。
1.8
P5142:区间方差,写过一遍了,有三倍经验。
P6327:和角公式 \(\sin(a+x)=\sin a\cos x+\cos a\sin x\),\(\cos(a+x)=\cos a\cos x−\sin a\sin x\),线段树乱维护即可。
P4588:每个操作当成一个数,2 操作相当于将第 \(pos\) 个数和自身改为 \(1\),查询只需要前缀积。
CF438D:性质:如果 \(p<x\),则 \(x \bmod p<\large\frac x2\),证明只需要分类讨论 \(p\) 与 \(\large\frac x2\) 的大小。于是区间取模只需要暴力,因为最多进行 \(\log x\) 次,并且当区间最大值小于 \(p\) 时就可以直接跳过,跟以前做的区间开方题差不多。
1.13
P2894:维护区间最长空房,类似线段树最大子段和维护即可,查询记得判断跨区间的情况。
P3569:令第 \(i\) 张牌较小值为 \(a_i\) 较大值为 \(b_i\)。维护区间头选 \(a\) 或 \(b\),尾最小选多少,合并区间贪心即可,查询直接查根节点。
P2221:将 \(v_i\) 看作收费站 \(i\) 到 \(i+1\) 的花费,于是不存在 \(v_n\)。然后推柿子,最后
上面的线段树维护,搞完求个 \(\gcd\) 输出即可。还是太菜,这垃圾式子推了 20 分钟。
P4198:显然一个斜率递增的子序列长度就是答案,注意不是最长上升子序列,因为能选就必须选。维护区间答案和最大值,合并区间时答案就是左区间答案加右区间大于左区间最大值的递增序列长度,后面这个东西分治搞搞即可。\(O(n\log n^2)\)。
1.14
今天学可持久化线段树,题目大多是 HDU 或本校 OJ 的,链接就不放了,做法也不写了。
其中第 7 题是树上问题,第 4,5 题比较牛逼,其它全板子。
主席树真的很苟,数据结构费脑子。
1.15
数据结构好神,一个上午只写两道题。。。然后昨天题 AK 了。
P2839:中位数考虑二分答案,将 \(<mid\) 的变成 \(-1\),将 \(\ge mid\) 的变成 \(1\),求和,如果 $\ge 0 $ 则考虑增大,否则减小。注意到 \([b+1,c-1]\) 是确定的,那么我们要尽可能在 \([a,b]\) 和 \([c,d]\) 多选 \(1\),所以维护前缀后缀最大值。接下来考虑怎么处理变成 \(1\) 和 \(-1\),先离散化,因为由 \(mid\) 变成 \(mid+1\) 只会把 \(mid\) 由 \(1\) 变成 \(-1\),只涉及单点修改,并且需要可持久化,主席树解决问题。(代码巨nm难写)
P3402:可持久化并查集,只需要将 \(fa\) 数组可持久化,但是不加优化一个链就能卡掉,路径压缩是均摊 \(O(\log n)\) 的,我们需要稳定的 \(O(\log n)\) 优化,于是考虑启发式合并(按秩合并),将小的接到大的,于是再维护一个可持久化的 \(sz\) 数组即可。
1.16-1.17
杀疯了,两天树剖写了 14 题。
树剖真的很难写,这些 sb 出题人线段树维护的和询问的都不一样,搞得每次改一大堆。
此生不碰树剖。
P4116:可以剖完以后用 set 维护每个 \(top_u\),然后进行插入和删除操作。线段树写法就优先找靠前的。
P3038:将边权变成深度更深的点的点权,那么 \(u,v\) 路径上的所有边权就是除 \(lca\) 外的所有点权,只需要在跳到同一条重链以后,\(id_u\) 改为 \(id_u+1\),即往下跳一格。
P4114:同理边权转点权。
P2146:install
操作就把从 \(x\) 到 \(1\) 的路径上全改成 \(1\),uninstall
操作就把 \(x\) 的子树全改成 \(0\),而同一颗子树的 \(id\) 连续,可以直接维护。查询就输出上一次的 \(1\) 个数与操作完后的 \(1\) 个数之差的绝对值。
P4315:线段树维护俩标记,先覆盖后加。
P1505:这是个线段树题,你把线段树写出来就没树剖啥事了,细节很多,调了 2 个小时。
P2486:线段树维护区间答案,区间左右颜色,合并时如果端点相同答案减 \(1\),树剖跳重链时同理,得记一下上一次的颜色。
P7735:NOI 题,比较厉害。将每次修改操作看作把 \(u,v\) 上的所有点染成独一无二的的颜色,那么这条边是重边的充要条件就是两端点颜色相同,那么询问就是求路径上有多少个长度为 \(2\) 的相同颜色段。和上一题维护相同的线段树,合并时大同小异。
P3979:换根的树剖,如果真的换根,根本不可做,于是就把 \(1\) 当根。设当前根为 \(root\),查询 \(x\),如果 \(x=root\) 那就是整棵树的答案;如果 \(x\) 在 \(root\) 到 \(1\) 的路径上,那么答案会变成整个树减去 \(root\) 所在 \(x\) 的那一颗子树的答案,都是连续区间,分成两块区间查询即可;否则答案不变。
LOJ6669:神奇交互,参考了 @stoorz 的博客,感谢。先询问 \(1\ x\) 得到所有点的深度,假设现在已经还原了前 \(i-1\) 层,要求还原深度为 \(i\) 的 \(x\)。先令 \(y=1\),找到 \(y\) 所在重链离 \(y\) 最远的点 \(z\),询问 \(dis(x,z)\),由 \(dep_x+dep_z-2dep_{lca(x,z)}=dis(x,z)\) 可知 \(lca(x,z)\) 的深度,由于重链上的点深度互不相同,于是可以求出 \(lca(x,z)\),所以我们可以确定 \(x\) 的一个祖先是 \(lca(x,z)\) 除 \(z\) 所在子树外的另一棵子树,令 \(y\) 等于这颗子树的根节点,继续执行以上操作直至 \(dep_y=dep_x-1\) 即可确定 \(fa_x=y\)。由于轻链数量不超过 \(\log n\),所以操作次数为 \(n+n\log n\),配合树剖超小常数即可通过。
1.18
cdq 分治,感觉非常脑残,三维四维多维偏序,出题的有多无聊。
P2617:动态区间第 \(k\) 小,可以直接树状数组套线段树。然而我写了分块,成功达成最劣解。每个块维护升序序列,修改暴力重构,查询散块暴力,整块二分。
P3157:找 cdq 分治找到的,我当然继续分块,让块长为 \(1000\),总共 \(100\) 个块,每个块维护一个树状数组,查询时散块暴力,整块树状数组。
1.19-1.26
过年放假,有时间就写题,寒假作业还没写。
P4587:假设当前能凑出来 \([1,now]\),则当 \(x\le now+1\) 时,就能凑出 \([1,now+x]\)。假设现在已选值域为 \([1,lst]\) 的数,能凑出 \([1,now]\),则我们把 \([1,now+1]\) 的数放进去都是合法的,但因为已经放了 \([1,lst]\),于是把 \([lst+1,now+1]\) 的数全丢里面去,求和后记为 \(sum\),那么选完以后已选值域为 \([1,now+1]\) 能凑出 \([1,now+sum]\)。答案的增长类似斐波那契数列,是常数级别的。
1.27-1.28
学习莫队,见 这篇文章。
做的题没写进去,没时间了,马上开学了,sb学校还有入学测试,服了,写完寒假作业还要复习,脑壳疼,只能不定时更新了。