Codeforces-960E

题解

奇数个点组成的路径才对答案有贡献
具体的解法是对每个点计算它对答案的贡献
每个点(设为$u$)对答案的贡献有两部分

  • 路径中除$u$外所有点都是在$u$的子孙节点中
    即在$u$的任意两个子树中各取一个点$v_1,v_2$,使$v_1,v_2$到$u$组成的路径同时有奇数个点或同时为偶数个点。这样从$v_1$到$v_2$,经过$u$的路径中含有奇数个点,能对答案有贡献,到$u$路径为奇数个点的做正贡献,为偶数的做负贡献。通过dfs可处理,(语言不好描述,详见代码)
    设$odd[i]$为$i$点 自身 和的子孙节点中由该点到$i$组成的路径含有奇数个点的个数
    $even[i]$为$i$点的子孙节点中由该点到$i$组成的路径含有偶数个点的个数
  • 路径中一部分是$u$的祖先节点,一部分是$u$的子孙节点
    这里有个重要结论
    设$allodd[i],alleven[i]$为图中所有点中到该点组成路径含有奇数点(偶数点)的个数
    设$1$为根节点,则
    $$allodd[1]=odd[1]\\alleven[1]=odd[1]$$
    同时若$u,v$为相邻的两个点
    $$allodd[u]=alleven[v]\\alleven[u]=allodd[v]$$
    设节点高度为$level[i],level[1]=1$
    则$$\begin{cases}
    allodd[i]=allodd[1]=odd[1],alleven[i]=alleven[i]=even[1] & level[i]\%2=1\\
    allodd[i]=alleven[1]=even[1],alleven[i]=allodd[i]=odd[1] & level[i]\%2=0\\
    \end{cases}$$
    设 $upo,upe$:该点自身和祖先节点中到该点组成的路径含奇数(偶数)个点的点的个数。
    $$upo=allodd[i]-odd[i]+1\\upe=alleven[i]-even[i]$$
    此点的贡献为
    $$
    (allodd[i]\times odd[i]-alleven[i]\times even[i])\times 2\times val[i]-val[i]
    $$
    注意当路径长度为1时,只能做一次贡献,而式子中是乘以2的,答案最后应减去一个$val[i]$

    代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    //4 18
    #include <iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;

    typedef long long ll;
    const ll MAXN=2e5+100;
    const ll MOD=1e9+7;
    struct Edge{
    ll from,to,nxt;
    }edge[MAXN*2];
    ll eidx;
    ll head[MAXN];
    void addedge(ll from,ll to)
    {
    edge[eidx].from=from; edge[eidx].to=to;
    edge[eidx].nxt=head[from]; head[from]=eidx++;
    }
    void einit()
    {
    eidx=0;
    memset(head,-1,sizeof head);
    }

    ll val[MAXN];
    ll o[MAXN],e[MAXN],lev[MAXN];
    ll ans;
    bool vis[MAXN];
    void dfs(ll u,ll h,ll fa){
    lev[u]=h;
    vis[u]=1;
    o[u]=e[u]=0;
    for(ll i=head[u];i!=-1;i=edge[i].nxt)
    {
    ll v=edge[i].to;
    if(vis[v]) continue;
    dfs(v,h+1,u);
    ll ta=2*(o[u]*e[v]%MOD-o[v]*e[u]%MOD)%MOD*val[u]%MOD;
    ta=(ta%MOD+MOD)%MOD;
    if(u==1)
    {
    //printf("ou %lld eu %lld ta %lld\n",o[u],e[u],ta);
    }
    ans=(ans+ta)%MOD;
    o[u]+=e[v];
    e[u]+=o[v];

    }
    o[u]++;
    }
    void init()
    {
    memset(vis,0,sizeof vis);
    }
    int main()
    {
    //freopen("input.txt","r",stdin);
    ll n;
    //while(cin>>n)
    {
    cin>>n;
    einit();
    init();
    for(int i=1;i<=n;++i){
    scanf("%lld",&val[i]);
    }
    for(int i=1;i<n;++i)
    {
    ll p1,p2;
    scanf("%lld%lld",&p1,&p2);
    addedge(p1,p2);
    addedge(p2,p1);
    }
    ans=0;
    dfs(1,1,-1);
    for(int i=1;i<=n;++i)
    {
    ll upo,upe,ta;
    if(lev[i]%2)
    {
    upo=o[1]-o[i]+1;
    upe=e[1]-e[i];
    }else{
    upo=e[1]-o[i]+1;
    upe=o[1]-e[i];
    }
    ta=2*(upo*o[i]%MOD-upe*e[i]%MOD)%MOD*val[i]%MOD;
    ta-=val[i];
    ta=(ta%MOD+MOD)%MOD;
    ans=(ans+ta)%MOD;
    }
    cout<<ans<<endl;
    }
    return 0;
    }