P15875 [ICPC 2026 NAC] Acorn Quarrels 题解

题目链接:P15875 [ICPC 2026 NAC] Acorn Quarrels

考虑最终状态和初始状态一样较为困难,可以考虑一个更强的东西:每条边恰好来回输送一次,这种情况下初始和最终状态显然是一样的,于是考虑构造每个松鼠在轮到他时均偷相邻的松鼠一个。

设轮到 $ u $ 时,$ u $ 周围的点的权值都为 $ ar_u $,设 $ cnt_{u,v} $ 代表轮到 $ u $ 时 $ v $ 被抢了多少次,那么对于一条边 $ u-v $,其中 $ u $ 是 $ v $ 的父亲,有:

\[d_v=ar_u+cnt_{u,v}-[v<u](deg_v) \]

\[ar_v=d_u-cnt_{v,u}+[u<v](deg_u) \]

注意到如果将一个点连的点排序,则其儿子的 $ cnt_{u,v} $ 可以根据 $ v $ 之前的点数量计算,于是只用预处理 $ cnt_{v,u} $ 即可。

代码:

#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);}
vector<int> e[100005];
int ar[100005],d[100005],cnt[100005],mn=0;
void dfs(int u,int fa)
{
	for(auto v:e[u])
	{
		if(v==fa)continue;
		if(v<fa)cnt[u]++;
		dfs(v,u);
	}
}
void solve(int u,int fa)
{
	int nw=0;
	for(auto v:e[u])
	{
		nw++;
		if(v==fa)continue;
		d[v]=ar[u]+cnt[v]-(v<u)*e[v].size();
		ar[v]=d[u]-nw+1+(u<v)*e[u].size();
		mn=min(mn,d[v]);
		solve(v,u);
	}
}
signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	int n=read();
	for(int i=1;i<n;i++)
	{
		int u=read(),v=read();
		e[u].pb(v);
		e[v].pb(u);
	}
	for(int i=1;i<=n;i++)
	{
		sort(e[i].begin(),e[i].end());
	}
	dfs(1,0);
	solve(1,0);
	for(int i=1;i<=n;i++)
	{
		writech(d[i]-mn+n,' ');
	}
	Code by MCYYDS
}

posted @ 2026-07-14 03:40  MCYYDS  阅读(7)  评论(0)    收藏  举报