cojs 简单的最近公共祖先 解题报告

我曾经自己想过每考试一次就从考试题中找找idea来出题

这次又找到了一个,先不管原来的考试题是什么

考试题中其中的一部分就是今天的这道题目啦

当时考场上自己比较傻,没有注意到有用的性质,套用了之前黑白树系列的做法

写的是log^2n的,结果导致只能在开O2的情况下A掉这道题目

后来仔细研究了以下,得到了本题的做法

首先我们观察操作中和黑白树系列的那道题目的区别

1、只有染黑操作,没有染白操作

2、不需要可持久化,不需要满足可减性

之后观察题目的性质:

1、转化成暴力写法,每次修改u到根的路径,查询u到根的路径

我们知道修改和查询路径我们可以利用树链剖分+线段树在log^2n的时间内完成

但是仔细考虑性质我们会发现每次修改和查询的一个端点都是根

对于一条链而言,我们每次修改只会修改这条链的顶端top到某个点的值

而又因为只有染黑操作,我们一旦把这条链的顶端top到某个点都染黑之后,这段不可能在被染白回去

那么很明显我们不需要用线段树,可以机智的去掉线段树的那个log

具体做法如下:

我们树链剖分,对于每条链维护一个点u并记录顶端top

每次更新的时候只需要观察更新点的深度是否大于u即可

每次更新是O(1)的,每次最多修改logn条链,修改操作时间复杂度logn

对于查询,我们从u节点向上跳链,如果当前链被修改过,证明答案一定在这条链上

之后我们考虑这条链记录的值u‘的深度,如果大于当前跳到的点u,则答案就是u

否则就是u’

我们每次最多跳logn条链,所以查询时间复杂度logn

至于C操作,时间戳就O(1)啦

总时间复杂度mlogn,常数非常小

在我把考试题的这部分改成这个写法之后就可以在不开O2的情况下A了,而且用时大概是时限的一半

下面说一下有关于出这道题目的一些心得:

1、这个题目的做法我不确定是最优的,可能会有并查集或者O(n)的做法之类的(不过估计需要离线)

如果有更优的做法欢迎与我讨论

2、有关于卡住log^2n:

首先这道题之前的做法是倍增+树状数组,由于维护子树和可以支持染白和可持久化

我一开始调整了树的深度和修改的次数(因为修改是log的,只有查询是log^2的)

使得这个做法会T掉几个点,但是后来我发现由于倍增数组,内存并不兹磁这个做法QAQ

还有一种更显然的做法是树链剖分+线段树,这样修改和查询都是log^2的

这个做法我没有刻意去卡,因为不卡他也会T掉

还有一种做法是上面的优化,就是整条链的修改直接在链上打标记,不维护全局线段树,对于每个链单独开线段树

这样常数会小很多,每次查询的时候只需要跳到第一个有修改标记得链,在线段树上二分就可以了

查询就是log的了,修改还是log^2的

我写了一发,不是很难写,可以过9个点,常数写的比我漂亮一点貌似就能A了

时间: 2024-10-11 11:42:07

cojs 简单的最近公共祖先 解题报告的相关文章

最近公共祖先 解题报告

最近公共祖先 问题描述 给定一棵\(n\)个节点的有根树,节点编号为\(1\sim n\),其中根节点为\(1\)号节点.每个节点都对应着一种颜色(黑/白)和一个固定的权值,初始时所有节点的颜色都为白色.现在你需要实现以下两种操作: \(\tt{Modify \ v}\):将节点\(v\)的颜色改成黑色: \(\tt{Query \ v}\):找到一个黑色节点\(u\),使得节点\(u\)和\(v\)的最近公共祖先\(z\)对应的权值尽可能大,输出节点\(z\)的权值.如果不存在黑色节点,输出\

cogs 2478. [HZOI 2016]简单的最近公共祖先

2478. [HZOI 2016]简单的最近公共祖先 ★☆   输入文件:easy_LCA.in   输出文件:easy_LCA.out   简单对比时间限制:2 s   内存限制:128 MB [题目描述] 给定一棵有n个节点的有根树,根节点为1,每个节点有一个权值wi,求 即求所有无序节点对的LCA的权值之和. 树的节点编号为1~n,LCA表示两节点的最近公共祖先,即在它们的所有公共祖先中离根节点最远的节点. [输入格式] 第一行一个整数n,表示节点数. 第二行n个正整数,表示每个点的权值.

[BZOJ2946] [Poi2000]公共串解题报告|后缀数组

给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 单词个数<=5,每个单词长度<=2000 尽管最近在学的是SAM...但是看到这个题还是忍不住想写SA... (其实是不知道应该怎么用SAM做... 对于后缀数组而言,多个字符串的公共子串与两个处理起来并没有什么区别 只要在中间加一些没有用的字符,将多个字符串拼成一个字符串 然后二分答案,对于一个长度L,在一组除了开头其他height都>=L的区间中如果每个字符串的位置都出现过就可以 应该是第二次这么解决一道公共串的题了.. 然

[BZOJ2946][Poi2000]公共串解题报告|后缀自动机

鉴于SAM要简洁一些...于是又写了一遍这题... 不过很好呢又学到了一些新的东西... 这里是用SA做这道题的方法 首先还是和两个字符串的一样,为第一个字符串建SAM 然后每一个字符串再在这个SAM上跑匹配 然而我们最后要的答案是什么呢? 是某个在所有字符串中匹配长度最小值最大的状态子串 然后对于每一个字符串 我们可以记录它在每一个状态子串上的最大匹配长度 最后需要一个非常关键的转移 就是用当前节点的值更新fail指针指向的节点 比如这种情况 如果一次匹配到左边的三个节点,一次匹配到右边的两个

[codevs3160]最长公共子串解题报告|后缀自动机

给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 样例就觉得不能更眼熟啊...好像之前用后缀数组做过一次 然后发现后缀自动机真的好好写啊...(当然当时学后缀数组的时候也这么认为... 这道题直接把第一个串放到后缀自动机里 第二个串在上面做匹配,但是要注意匹配的时候不能乱搞... 刚开始写了一个类似KMP的东西...想想不对啊 毕竟有些节点的深度是不对的 然而后来发现,我们可以用一个变量tem来保存当前的长度值 如果可以继续匹配,这个值就+1 否则就开始用fail指针不停地退,直到退

最长公共子序列解题报告

if(x[i]==y[j]) f[i][j]=f[i-1][j-1]+1; else if(x[i]!=y[j]) f[i][j]=max(f[i-1][j], f[i][j-1]); 原决策 这一块其实动规方程是 f[i][j]=max(f[i-1][j-1]+(x[i]==y[j]), f[i][j-1], f[i-1][j]); 动规方程 可以联系到射箭一题 1 #include <stdio.h> 2 #define maxn 501 3 int x[maxn], y[maxn], f

cogs2478 简单的最近公共祖先 树形dp

填坑--链接:http://cogs.pro/cogs/problem/problem.php?pid=2478 题意:求出:. 日常题面不符系列--实际上这是个树归--从下向上,对于每个节点,他对于某个点做出的贡献就是子树的大小乘上(子树总大小减去这棵子树大小)再加上该点乘权值,用式子写就是$ans[root]=size[root]*(sum((size[root]-size[belong[v]]))+1)$. 递推即可. 1 #include<iostream> 2 #include<

hihoCoder 1062 最近公共祖先&#183;一 最详细的解题报告

题目来源:最近公共祖先·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 题目描述 小Ho最近发现了一个神奇的网站!虽然还不够像58同城那样神奇,但这个网站仍然让小Ho乐在其中,但这是为什么呢? “为什么呢?”小Hi如是问道,在他的观察中小Ho已经沉迷这个网站一周之久了,甚至连他心爱的树玩具都弃置一边. “嘿嘿,小Hi,你快过来看!”小Ho招呼道. “你看,在这个对话框里输入我的名字,在另一个对话框里,输入你的名字,再点这个查询按钮,就可以查出来……什么!我们居然有同一

2016.8.27一套简单的题解题报告

一套不错的题,需要相关资料的联系我咯 考试分析: 1.  由于题目的名字加上第一道题没读完时我以为是我最不擅长的treeDP(其实不得不说,树和图上的题我真的是不想写,一般都写不对,上课太不认真,这个弱点要加强训练),我直接跳到了最后一道题,明知考3h还用了30min去分析,不过还是感谢,这30min救了我两道题出来: 这套题的确还是比较简单,后两道题只要认真分析数据都不会有问题,也许是因为暑假切了贪心和递推,我对分析数据比较在行,第三题切完之后还有2h,不过没写高精的我有点慌,打算最后留一点时