2020CCPC绵阳C题 Code a Trie 字典树(签到题)

@

Gym102822C Code a Trie: 字典树

链接
传送门: here
题意
建议先浏览一遍题面代码。
给你一段构建字典树的代码:每个节点随机赋予一个权值,保证每个点权值都不相同。
再给你\(n(1e5)\)个字符串及其执行\(query\)函数后的结果,问满足这些结果的字典树最少节点数量。
每组数据字符串长度和不超过\(100000\)

思路
首先将字符串按照权值(即\(query\)后得到的答案)排序并依次插入进字典树。
对于具有相同权值字符串,他们返回答案的节点一定在字典树\(rt\)\(lca\)路径上的某点处。
对于只有一个字符串的权值,其\(lca\)就是他自己的末尾节点。
将所有权值对应字符串集合的\(lca\)标记一下,可以肯定的是每个节点只能作为一种权值的\(lca\)

假设有\(m\)个字符串权值相同,他们在\(lca\)后的出边是:\(a,b,c,d\)
可以肯定的是这四条出边对应节点的子树内不能有其他权值的\(lca\)节点。
我们将\(lca\)这些出边对应的节点标记为不可能存在的节点,即\(die[node]=1\)

确定一下无解情况:

  • 两个字符串相同但是权值不同。
  • 多个权值对应的\(lca\)是同一节点。
  • \(rt\)到某个\(lca\)路径上存在\(die\)节点。

再来确定一下\(dfs\)贪心求解过程,遍历到节点\(u\)

  • 如果\(u\)的某条出边的子树内没有\(lca\)节点,这个子树全部扔掉。
  • 如果\(u\)的某条出边的子树内有多个\(lca\)节点,那么节点\(u\)必须保留。
  • 如果\(u\)存在若干条出边的子树内仅有\(1\)\(lca\)节点:
    -- 如果\(u\)\(lca\)节点,这些子树只需要保留一个节点即可,即\(u\)的儿子。
    -- 如果\(u\)不是\(lca\)节点,可以完全抛弃一个子树,剩余子树处理同上。

为什么这样贪心是对的呢?一条条解答:

  • 这条出边子树内没有\(lca\)节点,我的\(query\)不会走到这里,当然可以全部抛弃掉呀。
  • 如果节点\(u\)不保留,代表\(u\)的子树都不保留,那这对应两个\(lca\)\(query\)势必会得到同一个答案才对,互相矛盾,所以\(u\)必须保留。
  • 这里分了两个情况:
    -- 这些子树内只有一个\(lca\)节点,那么我询问的时候提前结束肯定最优,也不会影响别人,所以只需要保留\(u\)的儿子。
    -- 因为\(u\)不是\(lca\),我可以把一个子树内的\(lca\)节点直接提到\(u\)来。

\(over!\)稍微复杂点的签到题罢了。

备注
下标写错找了一年bug。

godie(st[sid[j]], len[sid[j]]);
---->
godie(st[j], len[j]);
想die哦。

时间复杂度:\(O(nlog(n))\)
空间复杂度:\(O(\sum |s| *26)\)

AC_CODE
思路很简单,可惜我代码写的有点冗杂。
here

posted @ 2020-11-09 16:54  Cwolf9  阅读(582)  评论(0编辑  收藏  举报