hdu5909 Tree Cutting

http://www.elijahqi.win/archives/3542
Problem 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

Source
BestCoder Round #88

Recommend
wange2014 | We have carefully selected several similar problems for you: 6297 6296 6295 6294 6293
题意:求有多少子树他们的异或值恰好为x x在0~m-1之间
给定点权 子树表示联通非空子图
首先考虑dp
设dp[x][w]表示当前处于x节点 和x节点构成的子树异或值为w的有多少子树
那么直接暴力转移是n^3的考虑用fwt优化这个dp
代表异或
dp方程: d p [ x ] [ w ] = i j = w m 1 d p [ x ] [ i ] d p [ y ] [ j ] + d p [ x ] [ w ]
那么刚学习了fwt
贴资料https://blog.csdn.net/neither_nor/article/details/60335099
类似fft ntt我们首先暴力做是 n 2 但是我们可以预处理一下关于两个数组分别的一个正变化
然后再把他们的正变换乘起来 得到答案的正变换 最后再逆变换回去即可 这是整体思路
所以不管是fwt在 &,^,|三种运算下我们需要 做到的仅仅是正变换之后的数组相乘 然后等同于原要求乘完之后的正变化
参照异或运算 我们设 A = ( A 0 , A 1 ) 表示在当前这一个二进制位 我们分别按照0,1去划分一下
异或运算可以赋予一个意义
定义i和j之间的奇偶性为:i&j中为1的位数的奇偶性,若为偶数则奇偶性是0,若为奇数则奇偶性是1
那么i和k的奇偶性异或j和k的奇偶性等于i^j和k的奇偶性
c[i]=(a0-a1)*(b0-b1)
=(a0*b0+a1*b1-a1*b0-a0*b1)
=(a0*b0+a1*b1)-(a1*b0-a0*b1)
因为提到的性质所以可以将前面靠左 是为偶的 所以整体就是偶-奇 满足一开始说的正变换之后的数组相乘 然后等同于原要求乘完之后的正变化

最后逆变换的时候因为是按位来考虑 所以我们并不担心是否要倒着做回去 仍然可以和正变换时候一样的顺序来解决

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e3+100;
const int mod=1e9+7;
int dp[N][N],inv2=mod+1>>1,f0[N],n,m,T,ans[N],h[N],num;
struct node{
    int y,next;
}data[N<<1];
inline int inc(int x,int v){return x+v>=mod?x+v-mod:x+v;}
inline int dec(int x,int v){return x-v<0?x-v+mod:x-v;}
inline void fwt(int *x,int f){
    for (int i=1;i<m;i<<=1){
        for (int j=0;j<m;j+=i<<1){
            for (int k=0;k<i;++k){
                ll t1=x[j+k],t2=x[j+k+i];
                if (f==1){
                    x[j+k]=inc(t1,t2);x[j+k+i]=dec(t1,t2);
                }else{
                    x[j+k]=(ll)inc(t1,t2)*inv2%mod;x[j+k+i]=(ll)dec(t1,t2)*inv2%mod;
                }
            }
        }
    }
}
inline void dfs(int x,int fa){
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if (y==fa) continue;
        dfs(y,x);
        for (int j=0;j<m;++j){
            dp[x][j]=(ll)dp[x][j]*inc(f0[j],dp[y][j])%mod;
        }
    }for (int i=0;i<m;++i) ans[i]=inc(ans[i],dp[x][i]);
}
int main(){
    freopen("hdu5909.in","r",stdin);
    T=read();
    while(T--){
        n=read();m=read();memset(dp,0,sizeof(dp));memset(ans,0,sizeof(ans));
        memset(f0,0,sizeof(f0));f0[0]=1;fwt(f0,1);num=0;memset(h,0,sizeof(h));
        for (int i=1;i<=n;++i){
            int x=read();memset(dp[i],0,sizeof(dp[i]));
            dp[i][x]=1;fwt(dp[i],1);
        }
        memset(h,0,sizeof(h));num=0;
        for (int i=1;i<n;++i){
            int x=read(),y=read();
            data[++num].y=y;data[num].next=h[x];h[x]=num;
            data[++num].y=x;data[num].next=h[y];h[y]=num;
        }dfs(1,0);fwt(ans,-1);
        for (int i=0;i<m-1;++i) printf("%d ",ans[i]);printf("%d\n",ans[m-1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/elijahqi/article/details/80494632