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
}

浙公网安备 33010602011771号