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; }