HDU 5909 Tree Cutting

传送门

题意:

有一棵n个点的无根树,节点依次编号为1到n,其中节点i的权值为vi,
定义一棵树的价值为它所有点的权值的异或和。
现在对于每个[0,m)的整数k,请统计有多少T的非空连通子树的价值等于k。

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
令f[i][j]表示以i为根的子树中异或和为j的联通块个数,v为i儿子
f[i][j]+=f[i][k]*f[v][l]    (k^l==j)
发现转移其实可以写成这种形式:
$C_i=\sum_{j^k=i}A_j*B_k$
这和卷积有点类似,不过运算改成了异或
这里就要用到FWT(快速沃尔什变换)
就可以做到nlogn转移
转移完后记得在加上原来的f[i][j],因为你可以不选v
复杂度为$O(n^{2}logn)$
卡常,少取模,不要定义long long变量
这题还可以点分治
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 using namespace std;
  7 struct Node
  8 {
  9   int next,to;
 10 }edge[2501];
 11 int num,head[1501],Mod=1e9+7,inv2,tmp[2001],a[1001][2001],ans[2001],n,m;
 12 int gi()
 13 {
 14   char ch=getchar();
 15   int x=0;
 16   while (ch<'0'||ch>'9') ch=getchar();
 17   while (ch>='0'&&ch<='9')
 18     {
 19       x=x*10+ch-'0';
 20       ch=getchar();
 21     }
 22   return x;
 23 }
 24 void add(int u,int v)
 25 {
 26   num++;
 27   edge[num].next=head[u];
 28   head[u]=num;
 29   edge[num].to=v;
 30 }
 31 int qpow(int x,int y)
 32 {
 33   int res=1;
 34   while (y)
 35     {
 36       if (y&1) res=1ll*res*x%Mod;
 37       x=1ll*x*x%Mod;
 38       y/=2;
 39     }
 40   return res;
 41 }
 42 void FWT(int *A,int len)
 43 {int i,j,k;
 44   for (i=1;i<m;i<<=1)
 45     {
 46       for (j=0;j<m;j+=(i<<1))
 47     {
 48       for (k=0;k<i;k++)
 49         {
 50           int x=A[j+k],y=A[j+k+i];
 51           A[j+k]=x+y;
 52           if (A[j+k]>=Mod) A[j+k]-=Mod;
 53           A[j+k+i]=x-y+Mod;
 54           if (A[j+k+i]>=Mod) A[j+k+i]-=Mod;
 55         }
 56     }
 57     }
 58 }
 59 void UFWT(int *A,int len)
 60 {int i,j,k;
 61     for (i=1;i<m;i<<=1)
 62     {
 63       for (j=0;j<m;j+=(i<<1))
 64     {
 65       for (k=0;k<i;k++)
 66         {
 67           int x=A[j+k],y=A[j+k+i];
 68           A[j+k]=1ll*(x+y)*inv2%Mod;
 69           A[j+k+i]=1ll*(x-y+Mod)*inv2%Mod;
 70         }
 71     }
 72     }
 73 }
 74 void DP(int x,int y)
 75 {int i;
 76   for (i=0;i<m;i++)
 77     tmp[i]=a[x][i];
 78   FWT(a[x],m);
 79   FWT(a[y],m);
 80   for (i=0;i<m;i++)
 81     a[x][i]=1ll*a[x][i]*a[y][i]%Mod;
 82   UFWT(a[x],m);
 83   for (i=0;i<m;i++)
 84     {
 85       a[x][i]=a[x][i]+tmp[i];
 86       if (a[x][i]>=Mod) a[x][i]-=Mod;
 87     }
 88 }
 89 void dfs(int x,int pa)
 90 {int i;
 91   for (i=head[x];i;i=edge[i].next)
 92     {
 93       int v=edge[i].to;
 94       if (v!=pa)
 95     {
 96       dfs(v,x);
 97       DP(x,v);
 98     }
 99     }
100   for (i=0;i<m;i++)
101     {
102       ans[i]=ans[i]+a[x][i];
103       if (ans[i]>=Mod) ans[i]-=Mod;
104     }
105 }
106 int main()
107 {int T,i,x,u,v,j;
108   cin>>T;
109   inv2=qpow(2,Mod-2);
110   while (T--)
111     {
112       memset(head,0,sizeof(head));
113       num=0;
114       memset(a,0,sizeof(a));
115       memset(ans,0,sizeof(ans));
116       scanf("%d%d",&n,&m);
117       for (i=1;i<=n;i++)
118     {
119       x=gi();
120       a[i][x]=1;
121     }
122       for (i=1;i<=n-1;i++)
123     {
124       u=gi();v=gi();
125       add(u,v);add(v,u);
126     }
127       dfs(1,0);
128       for (i=0;i<m-1;i++)
129       printf("%d ",ans[i]);
130       printf("%d\n",ans[m-1]);
131     }
132 }

 

posted @ 2018-02-08 11:09  Z-Y-Y-S  阅读(324)  评论(0编辑  收藏  举报