[国家集训队] Tree I

借助这道题目把wqs二分讲明白

考虑如下一个问题:

现在一共有若干个物品,物品被分成两组,现在从中选出若干个物品,但是题目会给出某种限制(也就是在这种限制条件下,物品的选择不是随意的,所有选择集合中,只有一些集合符合题目给出的限制,这样的集合才可以被选择),这种限制只跟物品本身有关而跟其权值无关(i.e. 对一个相同的物品选择集合,其中的物品权值无论如何变化,这个集合的合法性都不改变),而且必须从第一类物品中选出p个,问如何选择最优

我们设g(x)表示从第一类物品选出x个且满足题目限制的最优答案,如果说g(x)是一个凹凸函数,那么就可以利用wqs二分

比如g长成下面这个样子

那么如果题目给出的p=9,那么答案就是g(9)=5

显然我们是不能求出g(x)的(否则可以直接输出了),我们要想办法把g搞出来

假设现在有一条直线,斜率为k,令其通过函数上的每一个点(注意函数是离散的),则有

通过(x0,g(x0))的直线方程就是yg(x0)=k(xx0)

我们给第一类物品的权值都减去k,然后不管p了,在题目的限制条件下跑出来一个值res,那么res是什么?

res其实就是上面画的所有直线的截距的最大值

为什么?我们将直线写成ykx=g(x0)kx0,注意现在k是已知量。在最初的情况下,假设我们对每个x0都跑出来了一个最优解g(x0),而在减k的情况下,每个x0的最优解就是g(x0)kx0(因为权值的变化不会影响限制)。由于现在我们不管p了,只在题目的限制条件下跑出来了一个最优解,那么就是我们遍历了所有x0取最优解的最优解,也就是max(g(x0)kx0);在方程ykx=g(x0)kx0中令x=0,则y的值就是截距,且值为g(x0)kx0,所有截距的最大值就是max(g(x0)kx0),刚好就是我们跑出来的这个值;而截距最大显然就是经过切点的直线,也就是说我们获得了切线

然后我们去检查此时第一类物品选出的个数,很显然可以根据这个个数与p的相对大小进行二分的调整,最终当第一类物品刚好选出p个的时候,我们将跑出来的res加上kx0即可获得题目要求的答案

然后这一道题目的g可以证明是有凹凸性的(然而我却没有看到一个严格的证明),但是现在还有一个问题,当我们二分的值为mid的时候跑出来的白边有比need多,二分的值为mid+1的时候跑出来的白边比need小(或者当我们二分的值为mid的时候跑出来的白边有比need少,二分的值为mid1的时候跑出来的白边比need多,下面以前者为例进行分析),这怎么办?

此时当然可以二分实数,然而很容易TLE,所以我们来考察函数

显然g(x)的值都是整数,而且题目又保证了有解,也就是说g(need)是存在的,我们考察g(need1)g(need)

image

显然斜率为tanθ,而tanθ=g(x)g(x1)1=g(x)g(x1)为整数,也就是说图中任意两个点之间的连线的斜率为整数

然后我们再来考察发生上述情况会怎么样,只有可能像这样:

其中绿色的是我们二分的斜率,然后我们的算法跑出来的是第三个红点(从左往右),我们需要第二个红点,当斜率减一的时候,就直接把三个红点都舍弃了

所以此时就有一个很简单的解决方法了:在Kruscal的排序中,点权相同的将白边摆在前面,然后再更新即可。由于我们是在选出白边不低于need条时更新答案,这样就可以保证在斜率为mid时,跑出来的一定是第三个点,根据上文提到的“res加上kx”,我们就可以直接更新答案了

还有这两篇博客一博客二还没看(由于wqs二分与费用流的关系很大,所以学了网络流之后再看)

update 2024.7.14

可以好好看看代码,注意不要每次二分都重新排序,而是最开始就将两类边分开,然后利用归并排序即可

posted @   最爱丁珰  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示