题意
给一颗树,树上每个点有权值val,定义 , 为点u到v的路径权值和。
题解
定义
表示经过点u的路径数量,因此
分类讨论
1.
,所以
2. 存在
,所以
3. 我们可以知道假如存在
,那么肯定能使得通过调整
,
,使得
,但是在这题中这样的两个点必定存在。证明:首先找到一个深度最大的叶子节点,那么其
,其父节点
,那么
由于2*n-1是奇数,因此
AC代码
#include<stdio.h>
#include<vector>
#define N 100005
using namespace std;
typedef long long ll;
vector<ll>vt[N];
ll a[N],dp[N],size[N],dep[N],Fa[N],n,ans,nowdep;
void dfs(ll u,ll fa)
{
dep[u]=dep[fa]+1;
Fa[u]=fa;
size[u]=1;
if(nowdep<dep[u])nowdep=dep[u],ans=u;
for(ll i=0;i<vt[u].size();i++)
{
ll to=vt[u][i];
if(to==fa)continue;
dfs(to,u);
size[u]+=size[to];
dp[u]+=(n-size[to]-1)*size[to];
}
dp[u]+=(n-size[u])*(size[u]-1);
dp[u]+=(n-1)*2+1;
}
int main()
{
ll T;
scanf("%lld",&T);
while(T--)
{
nowdep=0;
scanf("%lld",&n);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
vt[i].clear();
dp[i]=dep[i]=0;
}
for(ll i=0;i<n-1;i++)
{
ll u,v;
scanf("%lld%lld",&u,&v);
vt[u].push_back(v);
vt[v].push_back(u);
}
dfs(1,1);
ll sum=0;
for(ll i=1;i<=n;i++)
sum+=dp[i]*a[i];
if(sum==0)
{
printf("0\n");
continue;
}
ll flag=0;
for(ll i=1;i<=n;i++)
if(sum%dp[i]==0)
{
printf("1\n%lld\n",i);
flag=1;
break;
}
if(flag)continue;
printf("2\n%lld %lld\n",Fa[ans],ans);
}
}