noi.ac#15 题解

做了一下午还多,完全独立完成。

题意很简单:给树加一条边使得最大匹配数增加1。

什么样的边 (a,b) 满足条件呢?很明显,当且仅当存在一个最大匹配不选 a,b。此时加上 a,b 边后,(a,b) 构成新的匹配,匹配数 +1

我们把它变成 “存在一个最大匹配不选 a” 且 “存在一个最大匹配不选 b”。这事就好做了,删 a 后重新算最大匹配。树的最大匹配可以dp做,O(n)。这样再加上枚举就是 O(n2) 的。假设这样的点叫做 “可不选点”,设 c 为“可不选点”的数量,答案就是 c(c1)/2

最大匹配的做法:

f(u,0/1) 表示 u 子树中的最大匹配数,u 不选/选(强制)。

f(u,0)=f(v,0/1),f(u,1)=max{f(v,0)+vvf(v,0/1)}

f(u,1) 那个转移的意思是,既然 u 要选,那肯定要和其中一个儿子匹配,枚举和儿子 v 匹配,v 必须在子树里不选,而其它的儿子可以选或不选都行。

最后答案自然是 f(1,0/1),设 1 为树的根。

很遗憾这样不对。因为我们最开始做的转化不对。这事很好理解,因为“可以不选”并非独立的,可能我不选某个点的时候,就必须要选另外的某个点了。最简单的反例是一个三个点的链 (1,2),(2,3)。最大匹配显然为 1,但是不选 1 就要选 3 ,不选 3 就要选 1,虽然 13 都是 “可不选点”,但它俩不能同时不被选。简单来说,“可不选”不满足“合并性”,“全可不选”不代表“可全不选”。

因此正确的做法是:枚举 a,b 并删除,求剩下的树的匹配数,看是否不变。O(n3)

我们分两步做。枚举 a ,并删除,求匹配数看是否不变(如果这里就变了就不用再枚举 b 了)。若不变(此时树被切成了若干子树),枚举 b 并删除,此时看 b 所在的那个子树的匹配数是否不变即可,其它子树就不用看了因为没受影响一定不变。

那相当于求这样的一个东西:对于每个“可不选点”,把它切掉后剩下若干个子树,求每个子树里“可不选点”数量的和。

容易想到在dp时顺便记录下“可不选点”的数量,设为 g(u,0/1)。我们尝试写出 g 的转移式,发现了几个问题:

  • g 超级难转移,虽然也不是不可以转移
  • 注意到我们还需要做换根dp,那就得支持减去一个子树。本来做 f 就只能用 set 维护后面的 max 勉强支持减,gf 还复杂,这里笔者想不下去了,我认为要对 g 做换根dp是相当困难的。

总的来说就是十分困难。(事实上,我一半时间就是在搞这个,发现搞不出来)

一条路走不通了,试试看换条路走。哪里可以“换条路”呢?我们知道,在二分图中,最大匹配数+最大独立集=n。从而转化为考虑最大独立集。

最大独立集相关dp:

最大独立集的dp比最大匹配的dp简单很多,这也是转化成最大独立集的原因。

f(u,0/1) 表示 u 子树里,u 不选/选,最大独立集。
f(u,0)=f(v,0/1),f(u,1)=1+f(v,0)

每个 v 贡献是独立的,很容易进行减法从而支持换根dp。

加一条边匹配数增加 1,由于 n 不变,就相当于最大独立集数减小 1。最大独立集减小 1,当且仅当 a,b 都是最大独立集必选的点。此时,原来可以(且必须)选 a,b,现在它俩只能二选一了,最大独立集减小 1

和“可不选”不一样,一个必须选,另一个必须选,那么两个就都是必须选的,它具有 “合并性”,“全必选”等价于“必全选”。此时答案就是必选点个数选 2 个的方案数。

写出来发现又不对。这回又哪里不对了?仔细看一下,最大匹配数+最大独立集=n 只在二分图中成立,加一条边万一出来个奇环,就不是二分图了。不过加出来是偶环就是对的。

观察数据发现这样算出来总是偏大的并且大的不多。多算的也很明确,就是加一条边后,最大独立集减少了一个但是匹配数不变的方案数。此时由于 n 不变,最大独立集+最大匹配数=n-1 ,并且生成了一个 “奇环基环树”。

从而我们有必要研究什么样的“奇环基环树”的最大独立集+最大匹配数=n-1。研究一会发现无论怎么样的结论都很难解决原问题,因为结论都是基于环上的每个子树的,而我们很难把这个子树提取出来。

实不相瞒,我另一半时间就花在这了。

我们重新回想一下,发现有这样一个东西:

我们分两步做。枚举 a ,并删除,求匹配数看是否不变(如果这里就变了就不用再枚举 b 了)。若不变(此时树被切成了若干子树),枚举 b 并删除,此时看 b 所在的那个子树的匹配数是否不变即可,其它子树就不用看了因为没受影响一定不变。

这里删除后求匹配数都是在树上求的。此时还没加边,可以使用 “最大独立集+最大匹配数=n” 的结论。

注意删了一个点后,点数就变成 n1 了,此时匹配数不变意味着最大独立集减小 1,那也就是这个点是必选点。

从而,边 (a,b) 满足条件,当且仅当: a 是(最大独立集的)必选点,且 ba 子树里也是必选点。

参考上面那个没做下去的思路,我们维护 g(u,0/1) 表示在 f(u,0/1) 情况下的必选点个数。但我们发现有一个问题:如果 f(u,0)=f(u,1), 那要维护两种情况的必选点的交集。这不是问题,我们再设一个状态 g(u,2) 表示总的必选点数。当一边大时,就是那一边的 g,否则表示交集。

那可以写出转移:g(u,0)=g(v,2)g(u,1)=g(v,0)g(u,2) 是难点。

f(u,0)>f(u,1) 时,g(u,2)=g(u,0); 当 f(u,1)>f(u,0) 时,g(u,2)=g(u,1)

否则就是最麻烦的情况。此时 f(u,0)=f(u,1),也就是说 f(v,0/1)=1+f(v,0)

对于每个 v,它可能会选择 max(f(v,0),f(v,1)) (即 f(v,0/1))或者 f(v,0)。当 f(v,0)f(v,1) 时,这俩都是选 f(v,0)。此时必选点数贡献 g(v,0)

否则就是说 f(v,0)<f(v,1)。那它可能选 1 也可能选 0。必选点数贡献 g(v,2) ... 吗?

此时我们发现它的 g(v,2)=g(v,1),但我们希望它是一个交集。

再记一个状态 s(u) 表示,选 0 和选 1 的必选点的交集,不管 f(u,0)f(u,1) 的大小关系。 那此时应该是贡献一个 s(u)

我们发现上面求的这个东西是 f(u,0)=f(u,1) 情况下的 g(u,2),其实就是 s(u)。加上 s(u) 后,推一推发现,转移完整了。长这样:

g(u,0)=g(v,2)g(u,1)=g(v,0)s(u)=f(v,0)f(v,1)?g(v,0):s(v)g(u,2)={g(u,0)if.f(u,0)>f(u,1)g(u,1)if.f(u,1)>f(u,0)s(u)if.f(u,1)=f(u,0)

虽然它看起来十分丧心病狂,但也比匹配的那个转移简单很多,而且它有一个十分优秀的性质:贡献关于每个 v 独立。

从而我们容易写出一个换根dp (建议用结构体封装加和减,会十分简单)。

f,g,s 表示全局信息,即以 u 为根,整棵树的 f,g,s。举个例子 f(u,0) 就是整颗树,不选 u,最大独立集。它也就是删除 u 后的最大独立集。它可以换根dp得到。

关于如何求答案也很显然了:枚举必选点 a (即 f(a,0)<f(a,1)),求它的每个子树里有多少必选点,加起来即可。下面的子树直接用 g,但还有一个外子树,用 fa[a] 的全局信息减去 a 的信息即可得到。

代码

posted @   Flandre-Zhu  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示