树形DP_ Xor Path

树形DP,主要思想为:自根节点开始遍历,一直遍历到叶子节点,后从叶子节点开始将得到的信息不断向上传递,知道根节点为止。

题目描述:

给定一棵n个点的树,每个点有权值。定义表示  到  的最短路径上,所有点的点权异或和。

对于,求所有的异或和。

输入描述:

第一行一个整数n。

接下来n-1行,每行2个整数u,v,表示u,v之间有一条边。

第n+1行有n个整数,表示每个点的权值

输出描述:

输出一个整数,表示所有的异或和,其中。

示例1

输入

4
1 2
1 3
1 4
1 2 3 4

输出

5

说明

{\mathbb{path}(1,2)=A_1\ \mathbb{xor}\ A_2=3\\<br />\mathbb{path}(1,3)=A_1\ \mathbb{xor}\ A_3=2\\<br />\mathbb{path}(1,4)=A_1\ \mathbb{xor}\ A_4=5\\<br />\mathbb{path}(2,3)=A_2\ \mathbb{xor}\ A_1\ \mathbb{xor}\ A_3=0\\<br />\mathbb{path}(2,4)=A_2\ \mathbb{xor}\ A_1\ \mathbb{xor}\ A_4=7\\<br />\mathbb{path}(3,4)=A_3\ \mathbb{xor}\ A_1\ \mathbb{xor}\ A_4=6}

再将这6个数异或起来就可以得到答案5了。

 链接:https://ac.nowcoder.com/acm/contest/272/B
来源:牛客网

每个节点含有对应的权值,求解所有路径中,经过节点权值的异或和。

 一个数异或它本身为0,即偶数次异或本身为0,奇数次异或本身等于数字本身,所以,我们只要求解所有路径中,经过每一个节点的次数即可

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <deque>
#include <stack>
#include <map>
#include <set>
typedef long long ll;
const int maxn = 500100;
const int maxm = 1000100;
int head[maxm],next1[maxm],v[maxm],val[maxn];
ll times[maxn];
int n,k;

void Add_edge(int x,int y)
{
    v[k] = y;next1[k] = head[x];head[x] = k++;
    v[k] = x;next1[k] = head[y];head[y] = k++;
}
int dfs(int p,int f)
{
    int sum = 0;
    for(int i = head[p];i != -1;i = next1[i])
    {
        int vv = v[i];
        if(vv != f)
        {
            ll temp = dfs(vv,p);
            times[p] += (ll)temp * sum;       //子树之间的路径经过次数
            sum += temp;                      //当前节点子节点的节点数量
        }
    }
    times[p] += (ll)(n - sum -1) * sum;     //作为中间点,子树和其他节点路径中经过的次数
    times[p] += n-1;                        //本身作为重点经过的次数
    return sum + 1;
}
int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    int x,y;
    for(int i = 0;i < n-1;i ++)
    {
        scanf("%d%d",&x,&y);
        Add_edge(x,y);
    }
    for(int i = 1;i <= n;i ++)
        scanf("%d",val+i);
    dfs(1,0);
    int ans = 0;
    for(int i = 1;i <= n;i ++)
        if(times[i] % 2)
            ans ^= val[i];
    printf("%d\n",ans);
}

猜你喜欢

转载自blog.csdn.net/li1615882553/article/details/84672269