codeforces766E. Mahmoud and a xor trip(DP)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lwqq3/article/details/79968576

题意:给定一棵树 每个节点有权值 任意选两个点i和j满足i<=j其贡献为i到j路径所有点的xor和 求所用点对的和

题解:感觉带xor的题从位运算考虑会好很多 于是对于每个点枚举每一位 对于每一位dp[i][0]表示从i点开始这一位xor和为0的路径数 那么dp[i][1]同理

设j为这个点的儿子 那么转移就把他所有儿子的贡献加起来 如果i这一位为0 dp[i][0] += dp[j][0], dp[i][1] += dp[j][1] 为1同理
然后从1开始dfs一遍就可 最开始还奇怪假如1 - 3 - 2这样的图 dfs一遍好像答案不对 然而并不是 这样dfs统计的顺序是3 - 2, 1 - 3, 1 - 3 - 2.  3 - 2和2 - 3是一样的 所以具有正确性,听说这是种套路题.....
             
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll ans;
vector<int> g[100005];
ll q[100005];
ll dp[100005][2];

void dfs(int x, int fa, int pos)
{
    int c = q[x] >> pos & 1;
    dp[x][c] = 1;
    for(int i = 0; i < g[x].size(); i++)
    {
        if(g[x][i] == fa) continue;
        dfs(g[x][i], x, pos);

        ans += (1LL << pos) *  dp[x][1] * dp[g[x][i]][0];
        ans += (1LL <<pos) * dp[x][0] * dp[g[x][i]][1];
        if(c == 0) dp[x][0] += dp[g[x][i]][0], dp[x][1] += dp[g[x][i]][1];
        else dp[x][0] += dp[g[x][i]][1], dp[x][1] += dp[g[x][i]][0];
    }
}

int main()
{
    ans = 0;
    int n; scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%lld", &q[i]), ans += q[i];

    for(int i = 1; i < n; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }

    for(int i = 0; i < 20; i++)
    {
        memset(dp, 0, sizeof(dp));
        dfs(1, 0, i);
    }
    printf("%lld\n", ans);
    return 0;
}


阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页