HDU 5416 CRB and Tree (树形DP)

来源:互联网 发布:addictive drums2 mac 编辑:程序博客网 时间:2024/05/14 09:39

题目链接:传送门 

题意:

在一棵树上,给定一个函数F(u,v)表示从u到v的路径上的边的权值异或起来的结果,然后求F(u,v)=s有多少种情况。


分析:

设dp[u]表示点u到根节点的路径异或起来的值,然后F(u,v)=dp[u]^dp[v],我们设cnt[x]表示dp[u]=x的情况有多少种,那么在s不等于0的情况时ans[s] = sigma(cnt[i]*cnt[s^i]),注意s = 0 的情况。


代码如下:

#include <iostream>#include <cstring>#include <algorithm>#include <cstdio>using namespace std;const int maxn = 1e6+10;typedef long long LL;int dp[maxn];int head[maxn],ip;LL cnt[maxn];int n;struct nod{    int to,next,w;}edge[maxn];bool vis[maxn];void init(){    ip=0;    memset(head,-1,sizeof(head));    memset(cnt,0,sizeof(cnt));    memset(vis,0,sizeof(vis));}void add(int u,int v,int w){    edge[ip].to=v;    edge[ip].w=w;    edge[ip].next=head[u];    head[u]=ip++;}int mmax;void dfs(int u,int pre,int val){    for(int i=head[u];i!=-1;i=edge[i].next){        int v= edge[i].to;        if(v==pre) continue;        if(edge[i].w^val>mmax)            mmax = edge[i].w^val;        cnt[edge[i].w^val]++;        dfs(v,u,val^edge[i].w);    }}int main(){    int t,m;    scanf("%d",&t);    while(t--){        init();        scanf("%d",&n);        for(int i=0;i<n-1;i++){            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            add(u,v,w);            add(v,u,w);        }        mmax = 0;        dfs(1,1,0);        scanf("%d",&m);        cnt[0]++;        for(int i=0;i<m;i++){            int s;            scanf("%d",&s);            LL ans = 0;            for(int j=0;j<maxn;j++){                if((s^j)==j) ans=ans+(cnt[j]*(cnt[j]-1));                else ans = ans=ans+cnt[j]*cnt[s^j];            }            ans=ans/2;            if(s==0) ans=ans+n;            printf("%I64d\n",ans);        }    }    return 0;}/***4571 2 11 3 11 4 14 5 23 6 22 7 211231230**/


1 0
原创粉丝点击