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