1 条题解
-
0
自动搬运
来自洛谷,原作者为

harmis_yz
beiribaol,幻想,永恒。搬运于
2025-08-24 23:05:08,当前版本为作者最后更新于2025-07-02 15:07:27,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
莫名其妙的题。
分析
首先这题不需要求没有修改时 变成根的时间。要求的话大概是发现对于 变到 所需的时间是它其它兄弟节点为根的子树中前缀最小值不小于 的链的数量,然后处理一下。
但是这题需要我们让 变到根的时间最短,那么这个时间一定是 。因为我们存在答案上界是将 全部修改成 ,此时在 变成根以前是不会选择其它节点的。模拟一下发现可能会影响到 变成根的时间的点只会是 到 路径上所有点 的兄弟节点。只要存在一种修改方式,使得路径任意一个前缀,都满足 就行了。其中 是 到 路径上所有点的兄弟节点中最大的价值。
定义状态函数 表示让 满足条件的最小代价。那么一定有 。那么对于 来说, 一定是当前前缀路径上存在至少一个点 的兄弟节点 ,满足 。则对于 来说,我们可以选择将 变成 ,对于 的子树来说,可以选择将 变成 或将 变成 。
如果 的数量为 。则可看作将 变成 或将 变成 ,此时将 变成 更优。
如果 的数量大于 。若 子树点的最优策略均为 变成 ,则变不变 无所谓。若存在 的最优策略为删点,当 时,删的点要么是 中的一个,要么是 到 路径上点的兄弟节点中的一个,后者和 无关。当 时,如果将 变成 ,且满足 ,此时不劣。如果变成 的点满足 ,那么支持 的前提是将 变成 ,此时 的变化可以看作将 变成 ,无影响。
把上面的情况取交集,发现我们可以改变第一个满足 的点。
那么现在需要实现:快速加点或删点,快速查询第一个比 大的数的值,快速查询比 大的数的数量。可以任意维护,时间复杂度 。
我说的是不是莫名奇妙的。
代码
const int N=1e6+10; int n,q; int val[N],f[N]; vector<int> e[N]; multiset<int> st; il void dfs(int u,int fa){ for(auto v:e[u]) if(v!=fa) st.insert(val[v]); for(auto v:e[u]) if(v!=fa){ st.erase(st.find(val[v])); auto it=st.lower_bound(val[v]); int x=(it==st.end()?-1:(*it)); if(it!=st.end()) f[v]=f[u]+1,st.erase(st.find(x)); else f[v]=f[u]; dfs(v,u); if(~x) st.insert(x); st.insert(val[v]); } for(auto v:e[u]) if(v!=fa) st.erase(st.find(val[v])); } il void solve(){ n=rd; for(re int i=1;i<=n;++i) val[i]=rd; for(re int i=1;i< n;++i){ int u=rd,v=rd; e[u].push_back(v), e[v].push_back(u); } dfs(1,0); q=rd; while(q--) cout<<f[rd]<<"\n"; return ; }
- 1
信息
- ID
- 10730
- 时间
- 5000ms
- 内存
- 1000MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者