Jumping Monkey(CCPC网络赛重赛)
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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(并查集,逆向考虑)
ccpc网络赛 Jumping Monkey 逆向并查集,重构树技巧