P12479 [集训队互测 2024] 长野原龙势流星群 题解

题目地址:P12479 [集训队互测 2024] 长野原龙势流星群

考虑权值最大的节点显然联通块只有自身一个点,然后它父节点一定会加上他(显然不劣),然后这两个点就可以缩成一个点了,重新当一个点处理塞进优先队列即可。

  • 为什么dfs处理是错的

因为父亲可能需要儿子不需要的点,例如一个长为 3 的链,$ w_1=1, w_2=100, w_3=60 $,显然点 1 的最优联通块是取点 1,2,3 而不是 1,2。

代码:

#include<bits/stdc++.h>
#define time(null) chrono::steady_clock::now().time_since_epoch().count()
#define int long long
#define uint unsigned long long
#define debug() cout<<"come here\n"
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define pb push_back
#define Code return
#define by 0
#define MCYYDS ;
using namespace std;
int qpow(int a,int b,int p=INF){int ret=1;while(b){if(b&1)ret=(ret*a)%p;a=(a*a)%p;b>>=1;}return ret;}
inline int read(){int ret=0,f=1;char ch=getchar();while(ch<'0'||ch>'9')f=(ch=='-'?-1:f),ch=getchar();while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();return ret*f;}
inline void write(int x){if(x<0){putchar('-');write(-x);return ;}if(x>9)write(x/10);putchar((char)(x%10+48));}
inline void writech(int x,char ch){write(x);putchar(ch);}
int fa[200005];
int w[200005],f[200005],cnt[200005];
double ans[200005];
int find(int x)
{
	return f[x]==x?x:f[x]=find(f[x]);
}
struct node{
	int x,y,id;
	bool operator<(const node t)const{
		return (__int128)x*t.y<(__int128)y*t.x;
	}
};
priority_queue<node> q;
signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	int n=read();
	for(int i=2;i<=n;i++)
	{
		fa[i]=read();
	}
	for(int i=1;i<=n;i++)
	{
		w[i]=read();
		f[i]=i;
		cnt[i]=1;
		q.push({w[i],1,i});
	}
	while(q.size())
	{
		int u=q.top().id;
		q.pop();
		if(f[u]!=u)continue;
		ans[u]=(double)w[u]/cnt[u];
		f[u]=find(fa[u]);
		if(find(fa[u]))
		{	
			w[find(fa[u])]+=w[u];
			cnt[find(fa[u])]+=cnt[u];
			q.push({w[find(fa[u])],cnt[find(fa[u])],find(fa[u])});
		}
	}
	for(int i=1;i<=n;i++)
	{
		printf("%.9lf\n",ans[i]);
	}
	Code by MCYYDS
}

posted @ 2026-07-11 13:03  MCYYDS  阅读(4)  评论(0)    收藏  举报