题意
给一颗树,树上每个点有权值val,定义 Sum=Σ(D(u,v))(1<=u,v<=n) S u m = Σ ( D ( u , v ) ) ( 1 <= u , v <= n ) , D(u,v) D ( u , v ) 为点u到v的路径权值和。
题解
定义
dp[u]
d
p
[
u
]
表示经过点u的路径数量,因此
Sum=Σ(dp[u]∗val[u])
S
u
m
=
Σ
(
d
p
[
u
]
∗
v
a
l
[
u
]
)
分类讨论
1.
Sum=0
S
u
m
=
0
,所以
ans=0
a
n
s
=
0
2. 存在
Sum%dp[u]=0
S
u
m
%
d
p
[
u
]
=
0
,所以
ans=1
a
n
s
=
1
3. 我们可以知道假如存在
gcd(dp[u],dp[v])=1
g
c
d
(
d
p
[
u
]
,
d
p
[
v
]
)
=
1
,那么肯定能使得通过调整
val[u]
v
a
l
[
u
]
,
val[v]
v
a
l
[
v
]
,使得
Sum=0
S
u
m
=
0
,但是在这题中这样的两个点必定存在。证明:首先找到一个深度最大的叶子节点,那么其
dp[u]=2∗n−1
d
p
[
u
]
=
2
∗
n
−
1
,其父节点
dp[parent]=6∗n−1
d
p
[
p
a
r
e
n
t
]
=
6
∗
n
−
1
,那么
gcd(2∗n−1,6∗n−11)=gcd(2∗n−1,−8)
g
c
d
(
2
∗
n
−
1
,
6
∗
n
−
11
)
=
g
c
d
(
2
∗
n
−
1
,
−
8
)
由于2*n-1是奇数,因此
gcd(2∗n−1,−8)=1
g
c
d
(
2
∗
n
−
1
,
−
8
)
=
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);
}
}