HDU5909 Tree Cutting(树形DP + FWT)

题目

Source

http://acm.hdu.edu.cn/showproblem.php?pid=5909

Description

Byteasar has a tree T with n vertices conveniently labeled with 1,2,...,n. Each vertex of the tree has an integer value vi.

The value of a non-empty tree T is equal to v1⊕v2⊕...⊕vn, where ⊕ denotes bitwise-xor.

Now for every integer k from [0,m), please calculate the number of non-empty subtree of T which value are equal to k.

A subtree of T is a subgraph of T that is also a tree.

Input

The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.

In each test case, the first line of the input contains two integers n(n≤1000) and m(1≤m≤210), denoting the size of the tree T and the upper-bound of v.

The second line of the input contains n integers v1,v2,v3,...,vn(0≤vi<m), denoting the value of each node.

Each of the following n−1 lines contains two integers ai,bi, denoting an edge between vertices ai and bi(1≤ai,bi≤n).

It is guaranteed that m can be represent as 2k, where k is a non-negative integer.

Output

For each test case, print a line with m integers, the i-th number denotes the number of non-empty subtree of T which value are equal to i.

The answer is huge, so please module 109+7.

Sample Input

2
4 4
2 0 1 3
1 2
1 3
1 4
4 4
0 1 3 1
1 2
1 3
1 4

Sample Output

3 3 2 3
2 4 2 3

 

分析

题目大概说给一棵结点有权的树,定义一个连通块的价值为其所有结点点权异或和,问这棵树有几个价值为[0,m)的子图。

 

  • dp[u][m]表示以u结点为根的子树中,价值为m且包含u结点的子图的个数
  • 通过依次与各个儿子的状态值合并转移,合并利用FWT加速。。时间复杂度不明觉厉。。

 

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define M 1000000007LL
#define MAXN 1111

struct Edge{
    int v,next;
}edge[MAXN<<1];
int NE,head[MAXN];
void addEdge(int u,int v){
    edge[NE].v=v; edge[NE].next=head[u]; head[u]=NE++;
}

void FWT(long long *a,int n){
    for(int d=1; d<n; d<<=1){
        for(int m=d<<1,i=0; i<n; i+=m){
            for(int j=0; j<d; ++j){
                long long x=a[i+j],y=a[i+j+d];
                a[i+j]=(x+y)%M;
                a[i+j+d]=(x-y+M)%M;
            }
        }
    }
}
void UFWT(long long *a,int n){
    for(int d=1; d<n; d<<=1){
        for(int m=d<<1,i=0; i<n; i+=m){
            for(int j=0; j<d; ++j){
                long long x=a[i+j],y=a[i+j+d];
                a[i+j]=(x+y)*500000004LL%M;
                a[i+j+d]=(x-y+M)*500000004LL%M;
            }
        }
    }
}
void Convolution(long long *a,long long *b,int n){
    FWT(a,n); FWT(b,n);
    for(int i=0; i<n; ++i){
        a[i]=a[i]*b[i]%M;
    }
    UFWT(a,n);
}

int n,m;
int val[MAXN];

long long d[MAXN][1111];

long long A[1111],B[1111];

void dfs(int u,int fa){
    d[u][val[u]]=1;
    for(int i=head[u]; i!=-1; i=edge[i].next){
        int v=edge[i].v;
        if(v==fa) continue;
        dfs(v,u);
        memcpy(A,d[u],sizeof(A));
        memcpy(B,d[v],sizeof(B));
        Convolution(A,B,m);
        for(int i=0; i<m; ++i){
            d[u][i]+=A[i];
            d[u][i]%=M;
        }
    }
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&m);
        for(int i=1; i<=n; ++i){
            scanf("%d",val+i);
        }
        NE=0;
        memset(head,-1,sizeof(head));
        int a,b;
        for(int i=1; i<n; ++i){
            scanf("%d%d",&a,&b);
            addEdge(a,b);
            addEdge(b,a);
        }
        memset(d,0,sizeof(d));
        dfs(1,1);
        for(int i=0; i<m; ++i){
            long long ans=0;
            for(int j=1; j<=n; ++j){
                ans+=d[j][i];
                ans%=M;
            }
            if(i) putchar(' ');
            printf("%I64d",ans);
        }
        putchar('\n');
    }
    return 0;
}

 

posted @ 2016-10-28 20:18  WABoss  阅读(521)  评论(0编辑  收藏  举报