Jumping Monkey(CCPC网络赛重赛)

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Jumping Monkey(CCPC网络赛重赛)相关的知识,希望对你有一定的参考价值。

Jumping Monkey(CCPC网络赛重赛)

题意:

n个点的树,每个点有一个不同的值 a i a_i ai.现在一个猴子在树上,这个猴子从点u跳到点v当且仅当 a v a_v av是u到v最短路径上的最大值。如果没有点能跳将停止。
对于k∈[1,n],计算猴子在点k开始最多能跳的点数量

题解:

每次跳跃点u,u要是路径上的最大值。如果点权最大的那个节点(设为u),显然无论从哪里开始跳,都可以直接到达u,且无法越过u到达其他点,到达u后也不能再跳向其他结点。也就是说u是最优方案中最后一个到达的点。那u的位置已经被固定了,将u从树上去掉,对剩下的每个连通块都递归上述过程,这样确定的新树,深度就是其答案。
但是上述的递归不好实现,我们逆向考虑这个过程:我们将点权按照从小到大枚举,当前枚举到点u,将u作为所有与u相连的(必须是已经枚举过的,也就是点权比u小的)连通块的跟。这样得到的一颗新树,u是v的父亲,说明u的点权大于v,其原树中u与v之间存在边,那v就是到达它的所有父亲点,所以每个节点的深度就是答案
复杂度O(nlog n)

代码:

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
    x= 0;
    char c= getchar();
    bool flag= 0;
    while (c < '0' || c > '9')
        flag|= (c == '-'), c= getchar();
    while (c >= '0' && c <= '9')
        x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
    if (flag)
        x= -x;
    read(Ar...);
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime = clock ();
    freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn=2e5+9;
PII val[maxn];
bool vis[maxn];
int fa[maxn];
vector<int>vec[maxn];
vector<int>g[maxn];
int dep[maxn];
int find(int x){
	if(fa[x]==x)return x;
	return fa[x]=find(fa[x]);
}
void dfs(int u){
	
	for(auto v:g[u]){
		dep[v]=dep[u]+1;
		dfs(v);
	}
}
int main()
{
    //rd_test();
	int t;
	read(t);
	while(t--){
		int n;
		cin>>n;
		for(int i=1;i<=n;i++)vis[i]=0;
		for(int i=1;i<=n;i++)fa[i]=i;
		for(int i=1;i<n;i++){
			int u,v;
			read(u,v);
			vec[u].push_back(v);
			vec[v].push_back(u);
		}
		for(int i=1;i<=n;i++){
			read(val[i].first);
			val[i].second=i;
		}
		sort(val+1,val+1+n);
		for(int i=1;i<=n;i++){
			int u=val[i].second;
			vis[u]=1;
			for(auto v:vec[u]){
				if(vis[v]==0)continue;
				int fv=find(v);
				fa[fv]=u;
				g[u].push_back(fv);
			}
		}
		dep[val[n].second]=1;
		dfs(val[n].second);
		for(int i=1;i<=n;i++)cout<<dep[i]<<endl;
		for(int i=0;i<=n;i++){
			g[i].clear(); 
			vec[i].clear();
		}
	}
	return 0;
	
    //Time_test();
}




以上是关于Jumping Monkey(CCPC网络赛重赛)的主要内容,如果未能解决你的问题,请参考以下文章

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

2021CCPC网络赛重赛-题解

2021CCPC网络赛重赛-题解

ccpc网络赛 Jumping Monkey 逆向并查集,重构树技巧

CCPC网络赛2021中国大学生程序设计竞赛(CCPC)- 网络选拔赛(重赛) 签到题5题

[HDU 7136] Jumping Monkey | 并查集 | 逆向思维