2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛(重赛) Jumping Monkey(并查集,逆向考虑)

Posted issue是fw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛(重赛) Jumping Monkey(并查集,逆向考虑)相关的知识,希望对你有一定的参考价值。

LINK

考虑权值最大的节点为 z z z,那么其他所有点最后都是跳到这个点,且不能越过这个点到其他点

那么其实我们可以把所有其他节点的答案都加 1 1 1,相当于把 z z z删掉,分成若干个连通块

在最后跳到 z z z点之前的步骤中,只能在连通块中跳跃

于是对于连通块中的点再次递归的做上面的事情

不过这个过程不好维护,但是可以考虑逆向加点做,从最小的节点开始遍历

设当前从小到大枚举到的节点 u u u,会连通周围所有权值比自己小的那些连通块

这些连通块中的点答案都加 1 1 1,直接加复杂度很高,不妨我们让 u u u向周围连通块的根连一条边,然后合并所有连通块

同时 u u u成为这个新的连通块跟,这样最后从点权最大的节点往下 d f s dfs dfs一遍,深度就是答案

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int n,m,a[maxn],fa[maxn],deep[maxn];
vector<int>vec[maxn],V[maxn];
pair<int,int> w[maxn];
int find(int x){  return x==fa[x]?x:fa[x] = find( fa[x] );}
void dfs(int u,int fa)
{
	deep[u] = deep[fa]+1;
	for(auto v:vec[u] )
	{
		if( v==fa )	continue;
		dfs( v,u );
	}
}
int main()
{
	ios::sync_with_stdio( false ); cin.tie( 0 ); cout.tie( 0 );
	int t; cin >> t;
	while( t-- )
	{
		cin >> n;
		for(int i=1;i<=n;i++)	fa[i] = i;
		for(int i=1;i<n;i++)
		{
			int l,r; cin >> l >> r;
			V[l].push_back( r ); V[r].push_back( l );
		}
		for(int i=1;i<=n;i++)	cin >> a[i], w[i] = { a[i],i };
		sort( w+1,w+1+n );
		for(int i=1;i<=n;i++)
		{
			int u = w[i].second;
			for(auto v:V[u] )//枚举相邻的点 
			{
				if( w[i].first>a[v] )//已经被枚举过了
				{
					int fl = find( v );
					vec[u].push_back( fl );
					fa[fl] = u;
				} 
			}
		}
		dfs( w[n].second,0 );
		for(int i=1;i<=n;i++)	cout << deep[i] << "\\n";
		for(int i=1;i<=n;i++)	V[i].clear(), vec[i].clear();
	}
} 

以上是关于2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛(重赛) Jumping Monkey(并查集,逆向考虑)的主要内容,如果未能解决你的问题,请参考以下文章

2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛(重赛) Jumping Monkey(并查集,逆向考虑)

2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

赛后总结+部分题解2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

2016中国大学生程序设计竞赛(ccpc 杭州)题解报告