1 条题解

  • 0
    @ 2025-8-24 23:05:08

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar harmis_yz
    beiribaol,幻想,永恒。

    搬运于2025-08-24 23:05:08,当前版本为作者最后更新于2025-07-02 15:07:27,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    莫名其妙的题。

    分析

    首先这题不需要求没有修改时 uu 变成根的时间。要求的话大概是发现对于 uu 变到 faufa_u 所需的时间是它其它兄弟节点为根的子树中前缀最小值不小于 valuval_u 的链的数量,然后处理一下。

    但是这题需要我们让 uu 变到根的时间最短,那么这个时间一定是 depudep_u。因为我们存在答案上界是将 P(1,u)P(1,u) 全部修改成 infinf,此时在 uu 变成根以前是不会选择其它节点的。模拟一下发现可能会影响到 uu 变成根的时间的点只会是 uu11 路径上所有点 xix_i 的兄弟节点。只要存在一种修改方式,使得路径任意一个前缀,都满足 valxi>mxxival_{x_i}> mx_{x_i} 就行了。其中 mxximx_{x_i}xix_i11 路径上所有点的兄弟节点中最大的价值。

    定义状态函数 fuf_u 表示让 uu 满足条件的最小代价。那么一定有 fv{fu,fu+1}[vsonu]f_v \in \{f_u,f_{u}+1\}[v\in son_u]。那么对于 vv 来说,fv=fu+1f_v=f_u+1 一定是当前前缀路径上存在至少一个点 xx 的兄弟节点 yy,满足 valyvalvval_y \ge val_v。则对于 vv 来说,我们可以选择将 valvval_v 变成 infinf,对于 vv 的子树来说,可以选择将 valvval_v 变成 infinf 或将 valyval_y 变成 00

    如果 valyvalvval_y\ge val_v 的数量为 11。则可看作将 valvval_v 变成 infinf 或将 valyval_y 变成 00,此时将 valyval_y 变成 00 更优。

    如果 valyvalvval_y \ge val_v 的数量大于 11。若 vv 子树点的最优策略均为 valwval_w 变成 infinf,则变不变 valyval_y 无所谓。若存在 ww 的最优策略为删点,当 valwvalvval_w \le val_v 时,删的点要么是 yy 中的一个,要么是 wwvv 路径上点的兄弟节点中的一个,后者和 vv 无关。当 valv<valwval_v < val_w 时,如果将 valyval_y 变成 00,且满足 valyvalwval_y \ge val_w,此时不劣。如果变成 00 的点满足 valy<valwval_y < val_w,那么支持 ww 的前提是将 valvval_v 变成 infinf,此时 yy 的变化可以看作将 valvval_v 变成 infinf,无影响。

    把上面的情况取交集,发现我们可以改变第一个满足 valyvalvval_y \ge val_v 的点。

    那么现在需要实现:快速加点或删点,快速查询第一个比 xx 大的数的值,快速查询比 xx 大的数的数量。可以任意维护,时间复杂度 O(nlogn+q)O(n\log n+q)

    我说的是不是莫名奇妙的。

    代码

    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
    上传者