博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

CF. 966E. May Holidays(树剖/虚树 分块)

题目链接

是19年四五月看的题,但咕咕了


\(Description\)
给定一棵树,在树上每个点处有\(1\)个人,每个人有一个忍耐程度\(t_i\)。当一个人子树内放假的人数\(\gt t_i\)且他没有放假的时候,他会删库跑路。初始时所有人都没放假。有\(m\)次操作,每次将一个人由放假变为不放假或由不放假变为放假,然后输出一共有多少个人会删库跑路。
\(n,m\leq10^5,\ 0\leq t_i\leq n\)

\(Solution\)
\(Sol1\)
\(A_i=t_i-x\)\(x\)\(i\)子树内有多少人放假了。就是维护\(A_i\lt0\)且没有放假的人的个数。
树剖+分块。对DFS序分块。记\(s[i][j]\)为第\(i\)块内\(A_x=j\)且没放假的人的个数。每次修改只会影响一个位置的值,很容易维护。
一个空间上的优化是,记\(tag[i]\)为第\(i\)块的整体加标记。我们限制\(s\)的第二维在\([-D,D]\)范围内(只在这个范围内统计),这样空间就是\(O(块数*D)\)的。因为\(|tag[i]|\lt D\)时显然不会有\(x\)影响答案。而当\(tag\geq D\)时,暴力重构这个块即可。

\(Sol2\)
虚树+分块。对询问分块,每次处理\(O(B)\)个询问。容易发现树被分成了\(O(B)\)条链,同一条链上的点,被修改的值是相同的。
我们可以\(O(B)\)建出虚树。考虑如何回答每次询问。设\(A_i=t_i-x\),把每一条链上的点先按\(A_i\)排序,然后维护一个指针,表示当前第一个\(\lt0\)的位置在哪。将重复的\(A_i\)合并到一起,每次更新一条链最多只会移动一下指针,是\(O(1)\)的。排序可以用基数排序。
处理完\(B\)个询问后更新一下所有\(A_i\)即可。
复杂度\(O(\frac{n^2}{B}+nB)\),也就是\(O(n\sqrt n)\)


代码咕了(两年半了),见 http://codeforces.com/contest/966/status/E?order=BY_CONSUMED_TIME_ASC


posted @ 2021-05-11 11:40  SovietPower  阅读(94)  评论(0编辑  收藏  举报