时隔一年再回首FWT,我似乎有了新理解??
添加了原理的推导,以前就只有模板…
文章目录
- 引入
- or(或)卷积
- 原理
- FWT_or正变换
- FWT_or逆变换
- 模板
- and(与)卷积
- 原理
- FWT_and正变换
- FWT_and逆变换
- 模板
- xor(异或)卷积
- 原理
- FWT_xor正变换
- FWT_xor逆变换
- 模板
- 例题
- T1:Card Game
- T2:Tree Cutting
引入
第一次学习的时候,因为连FFTFFTFFT都没学懂
所以当时学FWTFWTFWT加之是在家里网课
就直接掉线无法连回——一直都是背板子,是完全没学懂啊
最近重新学习了一遍,就马上来完善一下只有模板的博客
学了FFTFFTFFT,我们知道是可以用来算多项式乘法的
h(x)=∑i+j=xf(i)×g(j)h(x)=\sum_{i+j=x}f(i)\times g(j)h(x)=i+j=x∑f(i)×g(j)
但是可不可以算其他的,改变i,ji,ji,j之间的关系限制呢??
{h(x)=∑i∣j=xf(i)×g(j)h(x)=∑i&j=xf(i)×g(j)h(x)=∑i⊕j=xf(i)×g(j)\left\{ \begin{aligned} h(x)=\sum_{i|j=x}f(i)\times g(j)\\ h(x)=\sum_{i\&j=x}f(i)\times g(j)\\ h(x)=\sum_{i⊕j=x}f(i)\times g(j)\\ \end{aligned} \right.⎩⎪⎪⎪⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎪⎪⎪⎧h(x)=i∣j=x∑f(i)×g(j)h(x)=i&j=x∑f(i)×g(j)h(x)=i⊕j=x∑f(i)×g(j)
|
表示二进制或运算
,&
表示二进制与运算
,⊕
表示二进制异或运算
怎么做呢??——还是按着FFTFFTFFT的思路来
考虑能不能将多项式转化一下,变成位对位相乘,最后转化回去就是所求多项式
这就是FWTFWTFWT完成的使命了!!
前人已经找到了规律,备矣,我只是记录规律的正确性
因为模仿FFT,所以n应该也为2的幂
,下文意义默认为2的幂
or(或)卷积
原理
求:
h(x)=∑i∣j=xf(i)×g(j)h(x)=\sum_{i|j=x}f(i)\times g(j)h(x)=i∣j=x∑f(i)×g(j)
定义多项式AAA转化规律A′[i]=∑i&j=iA[j]A'[i]=\sum_{i\&j=i} A[j]A′[i]=i&j=i∑A[j]
h′[y]=∑x&y=xh[x]h'[y]=\sum_{x\& y=x}h[x]h′[y]=x&y=x∑h[x]=∑x&y=x∑i∣j=xf[i]×g[j]=\sum_{x\& y=x}\sum_{i|j=x}f[i]\times g[j]=x&y=x∑i∣j=x∑f[i]×g[j]
i|j=x
表明i,j
都是x
的子集,而x
又是y
子集⇒\Rightarrow⇒i,j
是y
的子集
=∑i&y=i∑j&y=jf[i]×g[j]=\sum_{i\&y=i}\sum_{j\&y=j}f[i]\times g[j]=i&y=i∑j&y=j∑f[i]×g[j]=(∑i&y=if[i])×(∑j&y=jg[j])=(\sum_{i\&y=i}f[i] )\times(\sum_{j\&y=j}g[j])=(i&y=i∑f[i])×(j&y=j∑g[j])=f′[y]×g′[y]=f'[y]\times g'[y]=f′[y]×g′[y]
成功实现位对位相乘,yeah!!举国同庆
最近重温FFT,NTTFFT,NTTFFT,NTT竟然变成了懂原理,看代码看半天??
所以接下来说一下实现,思路是递归,写法是递推,都好懂
FWT_or正变换
考虑模仿FFTFFTFFT,也是不断/2/2/2,将时间复杂度降下去
设y<n2y<\frac{n}{2}y<2n,则有
h′[y]=∑x&y=xf[x]×g[x]h'[y]=\sum_{x\& y=x}f[x]\times g[x]h′[y]=x&y=x∑f[x]×g[x]
h′[y+n2]=∑x&(y+n2)=xf[x]×g[x]h'[y+\frac{n}{2}]=\sum_{x\&(y+\frac{n}{2})=x}f[x]\times g[x]h′[y+2n]=x&(y+2n)=x∑f[x]×g[x]
将h′[y+n2]h'[y+\frac{n}{2}]h′[y+2n]的子集xxx拆分成两类分别考虑
①:x<n2x<\frac{n}{2}x<2n,即二进制最高位是000,则有x&y=x&(y+n2)x\& y=x\&(y+\frac{n}{2})x&y=x&(y+2n)
∑x&y=xf[x]×g[x]=h′[y]\sum_{x\&y=x}f[x]\times g[x]=h'[y]x&y=x∑f[x]×g[x]=h′[y]
②:x>n2x>\frac{n}{2}x>2n
∑x&(y+n2)f[x]×g[x]\sum_{x\&(y+\frac{n}{2})}f[x]\times g[x]x&(y+2n)∑f[x]×g[x]
将情况②当成新的多项式继续往下FWTFWTFWT,长度砍掉一半,循环上面的操作
最后要将左半部分的答案加到右半部分
🍔
不断往下,然后把左边蓝色计算出来,再加给右边红色,从下往上递推
FWT_or逆变换
就是从上往下,先减掉再往下
模板
opt=1opt=1opt=1是正变换
void FWT_or( int *v, int f ) {for( int i = 1;i < n;i <<= 1 )for( int j = 0;j < n;j += ( i << 1 ) )for( int k = 0;k < i;k ++ )v[i + j + k] = ( v[i + j + k] + f * v[j + k] ) % mod;
}
and(与)卷积
原理
问:
h(x)=∑i&j=xf(i)×g(j)h(x)=\sum_{i\&j=x}f(i)\times g(j)h(x)=i&j=x∑f(i)×g(j)
定义多项式变换规律
A′[i]=∑i&j=iA[j]A'[i]=\sum_{i\&j=i}A[j]A′[i]=i&j=i∑A[j]
h′[y]=∑x&y=yh[x]h'[y]=\sum_{x\&y=y}h[x]h′[y]=x&y=y∑h[x]=∑x&y=y∑i&j=xf[i]×g[j]=\sum_{x\&y=y}\sum_{i\&j=x}f[i]\times g[j]=x&y=y∑i&j=x∑f[i]×g[j]
i&j=x
说明x
是i,j
的子集,而y
又是x
的子集⇒\Rightarrow⇒y
是i,j
的子集
=∑i&y=y∑j&y=yf[i]×g[j]=\sum_{i\&y=y}\sum_{j\&y=y}f[i]\times g[j]=i&y=y∑j&y=y∑f[i]×g[j]=(∑i&y=yf[i])×(∑j&y=yg[j])=(\sum_{i\&y=y}f[i])\times (\sum_{j\&y=y}g[j])=(i&y=y∑f[i])×(j&y=y∑g[j])=f′[y]×g′[y]=f'[y]\times g'[y]=f′[y]×g′[y]
FWT_and正变换
与FWT_or差不多的思路
设y≥n2y\ge \frac{n}{2}y≥2n
h′[y]=∑x&y=yf[x]×g[x]h'[y]=\sum_{x\&y=y}f[x]\times g[x]h′[y]=x&y=y∑f[x]×g[x]
h′[y−n2]=∑x&(y−n2)=(y−n2)f[x]×g[x]h'[y-\frac{n}{2}]=\sum_{x\&(y-\frac{n}{2})=(y-\frac{n}{2})}f[x]\times g[x]h′[y−2n]=x&(y−2n)=(y−2n)∑f[x]×g[x]
同样的将h′[y−n2]h'[y-\frac{n}{2}]h′[y−2n]符合条件的xxx分成两类来考虑
①:x≥n2x\ge \frac{n}{2}x≥2n
说明xxx最高位是111
不考虑xxx的最高位后,y−n2y-\frac{n}{2}y−2n仍是其子集
那么yyy也是xxx的子集
∑x&y=yf[x]×g[x]=h′[y]\sum_{x\&y=y}f[x]\times g[x]=h'[y]x&y=y∑f[x]×g[x]=h′[y]
②:x<n2x<\frac{n}{2}x<2n
∑x&(y−n2)=(y−n2)f[x]×g[x]\sum_{x\&(y-\frac{n}{2})=(y-\frac{n}{2})}f[x]\times g[x]x&(y−2n)=(y−2n)∑f[x]×g[x]
将此情况当成新的多项式继续往下求解
🍔:
从下往上算完后将右半部分红色加到左半部分蓝色里,再往上回溯
FWT_and逆变换
从上往下,先左减去右,再下放
模板
void FWT_and( int *v, int f ) {for( int i = 1;i < n;i <<= 1 )for( int j = 0;j < n;j += ( i << 1 ) )for( int k = 0;k < i;k ++ )v[j + k] = ( v[j + k] + v[j + k + i] * f ) % mod;
}
xor(异或)卷积
原理
问:
h(x)=∑i⊕j=xf(i)×g(j)h(x)=\sum_{i⊕j=x}f(i)\times g(j)h(x)=i⊕j=x∑f(i)×g(j)
定义多项式变换规律
A′[i]=∑cnt(i&j1)%2=0A[j1]−∑cnt(i&j2)%2=1A[j2]A'[i]=\sum_{cnt(i\&j_1)\%2=0}A[j_1]-\sum_{cnt(i\&j_2)\%2=1}A[j_2]A′[i]=cnt(i&j1)%2=0∑A[j1]−cnt(i&j2)%2=1∑A[j2]
cnt(i)cnt(i)cnt(i)表示iii二进制有多少个111
h′[y]=∑cnt(y&x1)%2=0h[x1]−∑cnt(y&x2)%2=1h[x2]h'[y]=\sum_{cnt(y\&x_1)\%2=0}h[x_1]-\sum_{cnt(y\&x_2)\%2=1}h[x_2]h′[y]=cnt(y&x1)%2=0∑h[x1]−cnt(y&x2)%2=1∑h[x2]=∑cnt(y&x1)%2=0∑i1⊕j1=x1f[i1]×g[j1]−∑cnt(y&x2)%2=1∑i2⊕j2=x2f[i2]×g[j2]=\sum_{cnt(y\&x_1)\%2=0}\sum_{i_1⊕j_1=x_1}f[i_1]\times g[j_1]-\sum_{cnt(y\&x_2)\%2=1}\sum_{i_2⊕j_2=x_2}f[i_2]\times g[j_2]=cnt(y&x1)%2=0∑i1⊕j1=x1∑f[i1]×g[j1]−cnt(y&x2)%2=1∑i2⊕j2=x2∑f[i2]×g[j2]
似乎卡住了,推不下去了??这可不行,证明不了正确性啊!
那没办法了,正着推不下去,老子倒着往回退可还行
仗着前人的正确性疯狂整
f′[x]×g′[x]f'[x]\times g'[x]f′[x]×g′[x]=(∑f[i]−∑f[j])×(∑g[i]−∑g[j])=(\sum f[i]-\sum f[j])\times (\sum g[i]-\sum g[j])=(∑f[i]−∑f[j])×(∑g[i]−∑g[j])cnt(x&i)%2=0,cnt(x&j)%2=1cnt(x\& i)\%2=0,cnt(x\&j)\%2=1cnt(x&i)%2=0,cnt(x&j)%2=1=∑f[i]g[i]+∑f[j]g[j]−∑f[i]g[j]−∑f[j]g[i]=\sum f[i]g[i]+\sum f[j]g[j]-\sum f[i]g[j]-\sum f[j]g[i]=∑f[i]g[i]+∑f[j]g[j]−∑f[i]g[j]−∑f[j]g[i]
这里需要抽象理解式子,才能建立关联,发现与h′[x]h'[x]h′[x]展开是一致的
不好意思我太菜了,建立不了关联——那就换一种证法
x&(i⊕j)≡x&i+x&j(mod2)x\&(i⊕j)\equiv x\& i+x\&j\ \ \ \ (mod\ \ \ 2)x&(i⊕j)≡x&i+x&j (mod 2)
我们采取暴力分类讨论智障求证,下面i,j,x
均表示其二进制某一位上为1/01/01/0
i=1,j=1,x=0
i⊕j=0,(i⊕j)&x=0i⊕j=0,(i⊕j)\&x=0i⊕j=0,(i⊕j)&x=0
x&i=0,x&j=0,x&i+x&j=0x\&i=0,x\&j=0,x\&i+x\&j=0x&i=0,x&j=0,x&i+x&j=0i=0,j=0,x=0
i⊕j=0,(i⊕j)&x=0i⊕j=0,(i⊕j)\&x=0i⊕j=0,(i⊕j)&x=0
x&i=0,x&j=0,x&i+x&j=0x\&i=0,x\&j=0,x\&i+x\&j=0x&i=0,x&j=0,x&i+x&j=0i=1,j=0,x=0
i⊕j=1,(i⊕j)&x=0i⊕j=1,(i⊕j)\&x=0i⊕j=1,(i⊕j)&x=0
x&i=0,x&j=0,x&i+x&j=0x\&i=0,x\&j=0,x\&i+x\&j=0x&i=0,x&j=0,x&i+x&j=0i=0,j=1,x=0
i⊕j=1,(i⊕j)&x=0i⊕j=1,(i⊕j)\&x=0i⊕j=1,(i⊕j)&x=0
x&i=0,x&j=0,x&i+x&j=0x\&i=0,x\&j=0,x\&i+x\&j=0x&i=0,x&j=0,x&i+x&j=0i=0,j=0,x=1
i⊕j=0,(i⊕j)&x=0i⊕j=0,(i⊕j)\&x=0i⊕j=0,(i⊕j)&x=0
x&i=0,x&j=0,x&i+x&j=0x\&i=0,x\&j=0,x\&i+x\&j=0x&i=0,x&j=0,x&i+x&j=0i=0,j=1,x=1
i⊕j=1,(i⊕j)&x=1i⊕j=1,(i⊕j)\&x=1i⊕j=1,(i⊕j)&x=1
x&i=0,x&j=1,x&i+x&j=1x\&i=0,x\&j=1,x\&i+x\&j=1x&i=0,x&j=1,x&i+x&j=1i=1,j=0,x=1
i⊕j=1,(i⊕j)&x=1i⊕j=1,(i⊕j)\&x=1i⊕j=1,(i⊕j)&x=1
x&i=1x&j=0,x&i+x&j=1x\&i=1x\&j=0,x\&i+x\&j=1x&i=1x&j=0,x&i+x&j=1i=1,j=1,x=1
i⊕j=0,(i⊕j)&x=0i⊕j=0,(i⊕j)\&x=0i⊕j=0,(i⊕j)&x=0
x&i=1,x&j=1,x&i+x&j=2x\&i=1,x\&j=1,x\&i+x\&j=2x&i=1,x&j=1,x&i+x&j=2
此情况注意是在取模2下,所以奇偶还是没变
将A′A'A′换一种表达方式
A′[i]=∑(−1)cnt(i&j)%2A[j]A'[i]=\sum (-1)^{cnt(i\&j)\% 2}A[j]A′[i]=∑(−1)cnt(i&j)%2A[j]
重新推一遍式子
科研就是不断失败重头再来!!
h′[y]=∑(−1)cnt(y&x)%2h[x]=∑(−1)cnt(y&x)%2∑i⊕j=xf[i]g[j]h'[y]=\sum(-1)^{cnt(y\&x)\%2}h[x]=\sum(-1)^{cnt(y\&x)\%2}\sum_{i⊕j=x}f[i]g[j]h′[y]=∑(−1)cnt(y&x)%2h[x]=∑(−1)cnt(y&x)%2i⊕j=x∑f[i]g[j]=∑(−1)cnt(y&(i⊕j))%2f[i]g[j]=∑(−1)cnt(y&i)+cnt(y&j)f[i]g[j]=\sum (-1)^{cnt(y\&(i⊕j))\%2}f[i]g[j]=\sum (-1)^{cnt(y\&i)+cnt(y\&j)}f[i]g[j]=∑(−1)cnt(y&(i⊕j))%2f[i]g[j]=∑(−1)cnt(y&i)+cnt(y&j)f[i]g[j]=∑(−1)cnt(y&i)f[i]×∑(−1)cnt(y&j)g[j]=\sum (-1)^{cnt(y\&i)}f[i]\times \sum (-1)^{cnt(y\&j)}g[j]=∑(−1)cnt(y&i)f[i]×∑(−1)cnt(y&j)g[j]=f′[y]×g′[y]=f'[y]\times g'[y]=f′[y]×g′[y]
FWT_xor正变换
有了前面两种简单的铺垫,这里的思路是一致的,不再写式子
当y<n2y<\frac{n}{2}y<2n
将符合条件的xxx同样分成两类
①:x<n2x<\frac{n}{2}x<2n
②:x≥n2x\ge \frac{n}{2}x≥2n
x&yx\&yx&y的111个数的奇偶性并没有发生改变
直接加起来
当y≥n2y\ge \frac{n}{2}y≥2n
将符合条件的xxx同样分成两类
①:x<n2x<\frac{n}{2}x<2n
②:x≥n2x\ge \frac{n}{2}x≥2n
情况②的x&yx\&yx&y最高位为111,个数奇偶性发生改变,前面带的符号变成负号
FWT(A)=(FWT(B)+FWT(C),FWT(B)−FWT(C))FWT(A)=(FWT(B)+FWT(C),FWT(B)-FWT(C))FWT(A)=(FWT(B)+FWT(C),FWT(B)−FWT(C))
FWT_xor逆变换
就相当于解一个二元一次方程,已知和差
IFWT(A)=(IFWT(B)+IFWT(C)2,IFWT(B)−IFWT(C)2)IFWT(A)=(\frac{IFWT(B)+IFWT(C)}{2},\frac{IFWT(B)-IFWT(C)}{2})IFWT(A)=(2IFWT(B)+IFWT(C),2IFWT(B)−IFWT(C))
模板
void FWT_xor( int *v, int f ) {for( int i = 1;i < n;i <<= 1 )for( int j = 0;j < n;j += ( i << 1 ) ) for( int k = 0;k < i;k ++ ) {int x = v[j + k], y = v[j + k + i];v[j + k] = ( x + y ) % mod;v[j + k + i] = ( x - y + mod ) % mod;if( f == -1 ) {v[j + k] = v[j + k] * inv % mod;v[j + k + i] = v[j + k + i] * inv % mod;}}
}
例题
听得懂原理:理解记忆模板
听不懂:强化训练
T1:Card Game
title
Alice and Bob now love to play a card game. Everyone is starting n cards, each card has no more than m attribute. Now they need finish Q tasks, each task will require everyone to give a card, and then make up the attribute types that the task demands (e.g. the task required attributes A, B, C, Alice’s card contains A B and Bob’s card contains B, C. they can use this union to finish the task).
For each task, How many ways that Alice and Bob can do this task.
Input
here are T cases. (T<=20) (about 5 test cases n>=1000 m>=12 Q>=1000)
For each test case.The first line contains two integers n,m(n<=100000, m<=18), which indicates the number of cards which each one has and total attributes.
The next line contain n binary numbers indicates the cards Alice has. The ith binary number m_i indicates the attributes each card have. (m_i <2^18)
(if m_i = 10011 , this card has the first, second and fifth attrtbutes)
he next line contain n binary numbers indicates the cards Bob has.
Then contain one integer Q which is the number of Tasks.
Then next Q lines, each contain one binary number q_i which indicates the attributes they need to make. (qi < 2^18)
Output
For each test case, you first output one line “Case #%d:”
Then output q lines, each line contains one which indicates the ways they can finish this task.
Sample Input
1
4 4
1001 11 1100 1000
1110 1001 10 100
2
1100
111
Sample Output
Case #1:
2
1
solution
板题,就是套FWT_orFWT\_orFWT_or
code
#include <cstdio>
#include <cstring>
#define mod 998244353
#define MAXN 200000
int n, m, N, Q;
long long A[MAXN], B[MAXN], v[MAXN], c[MAXN];
long long inv = ( mod + 1 ) >> 1;
char s[30];long long read() {scanf( "%s", s );int len = strlen( s );long long x = 0;for( int i = 0;i < len;i ++ )x = ( x << 1 ) + ( s[i] - '0' );return x;
}void FWT_or( long long *v, int opt ) {for( int i = 2;i <= N;i <<= 1 )for( int p = i >> 1, j = 0;j < N;j += i )for( int k = j;k < j + p;++ k )v[k + p] += v[k] * opt;
}int main() {int T, n, m;scanf( "%d", &T );for( int t = 1;t <= T;t ++ ) {printf( "Case #%d:\n", t );scanf( "%d %d", &n, &m );N = 1 << m;memset( A, 0, sizeof( A ) );memset( B, 0, sizeof( B ) );for( int i = 1;i <= n;i ++ ) A[read()] ++;for( int i = 1;i <= n;i ++ ) B[read()] ++;FWT_or( A, 1 ), FWT_or( B, 1 );for( int i = 0;i < N;i ++ )A[i] = A[i] * B[i];FWT_or( A, -1 );scanf( "%d", &Q );while( Q -- ) printf( "%lld\n", A[read()] );}return 0;
}
T2:Tree Cutting
title
Byteasar has a tree TTT with nnn vertices conveniently labeled with 1,2,...,n1,2,...,n1,2,...,n. Each vertex of the tree has an integer value viv_ivi.
The value of a non-empty tree TTT is equal to v1⊕v2⊕...⊕vnv_1\oplus v_2\oplus ...\oplus v_nv1⊕v2⊕...⊕vn, where ⊕\oplus⊕ denotes bitwise-xor.
Now for every integer kkk from [0,m)[0,m)[0,m), please calculate the number of non-empty subtree of TTT which value are equal to kkk.
A subtree of TTT is a subgraph of TTT that is also a tree.
Input
The first line of the input contains an integer T(1≤T≤10)T(1\leq T\leq10)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)n(n\leq 1000)n(n≤1000) and m(1≤m≤210)m(1\leq m\leq 2^{10})m(1≤m≤210), denoting the size of the tree TTT and the upper-bound of vvv.
The second line of the input contains nnn integers v1,v2,v3,...,vn(0≤vi<m)v_1,v_2,v_3,...,v_n(0\leq v_i < m)v1,v2,v3,...,vn(0≤vi<m), denoting the value of each node.
Each of the following n−1n-1n−1 lines contains two integers ai,bia_i,b_iai,bi, denoting an edge between vertices aia_iai and bi(1≤ai,bi≤n)b_i(1\leq a_i,b_i\leq n)bi(1≤ai,bi≤n).
It is guaranteed that mmm can be represent as 2k2^k2k, where kkk is a non-negative integer.
Output
For each test case, print a line with mmm integers, the iii-th number denotes the number of non-empty subtree of TTT which value are equal to iii.
The answer is huge, so please module 109+710^9+7109+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
solution
设dp[u][i]dp[u][i]dp[u][i]:表示以uuu为根的子树内,异或值为jjj的方案数
有一个很暴力的转移
dp[u][i]=∑j⊗k=idp[u][j]∗dp[v][k],v∈son[u]dp[u][i]=\sum_{j\otimes k=i}dp[u][j]*dp[v][k],v∈son[u]dp[u][i]=j⊗k=i∑dp[u][j]∗dp[v][k],v∈son[u]
发现直接可以FWT_xorFWT\_xorFWT_xor,直接dfsdfsdfs暴力做就降了一个mmm
code
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
#define mod 1000000007
#define ll long long
#define MAXN 1050
vector < int > G[MAXN];
const ll inv = ( mod + 1 ) >> 1;
int T, n, m, N;
ll ans[MAXN];
ll dp[MAXN][MAXN];void FWT( ll *w, int opt ) {for( int i = 2;i <= N;i <<= 1 )for( int p = i >> 1, j = 0;j < N;j += i )for( int k = j;k < j + p;k ++ ) {ll x = w[k], y = w[k + p];w[k] = ( x + y ) % mod;w[k + p] = ( x - y + mod ) % mod;if( opt == -1 )w[k] = w[k] * inv % mod, w[k + p] = w[k + p] * inv % mod;}
}void dfs( int u, int fa ) {FWT( dp[u], 1 );for( int i = 0;i < G[u].size();i ++) {int v = G[u][i];if( v == fa ) continue;dfs( v, u );for( int j = 0;j < N;j ++ )dp[u][j] = dp[u][j] * dp[v][j] % mod;}FWT( dp[u], -1 );dp[u][0] = ( dp[u][0] + 1 ) % mod;//一个子树是可以不选的 所以要+1FWT( dp[u], 1 );
}int main() {scanf( "%d", &T );while( T -- ) {scanf( "%d %d", &n, &m );memset( dp, 0, sizeof( dp ) );memset( ans, 0, sizeof( ans ) );for( int i = 1;i <= n;i ++ ) G[i].clear();N = m;for( int i = 1, x;i <= n;i ++ )scanf( "%d", &x ), dp[i][x] ++;for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v ), G[v].push_back( u );}dfs( 1, 0 );for( int i = 1;i <= n;i ++ )FWT( dp[i], -1 );for( int i = 1;i <= n;i ++ )dp[i][0] = ( dp[i][0] - 1 + mod ) % mod;for( int i = 1;i <= n;i ++ )for( int j = 0;j < m;j ++ )ans[j] = ( ans[j] + dp[i][j] ) % mod;printf( "%lld", ans[0] );for( int i = 1;i < m;i ++ )printf( " %lld", ans[i] ); printf( "\n" );} return 0;
}