题目描述:
树,带点权,连通块的权值为块中点权的异或和,求权值=
[
0
,
m
)
[0,m)
[0,m)的连通块的数量。
n
≤
1000
,
m
≤
2
10
n\le1000,m\le2^{10}
n≤1000,m≤210
题目分析:
此题可以设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示包含点
i
i
i的连通块权值为
j
j
j的数量,合并就用FWT优化,可以做到
O
(
n
m
l
o
g
m
)
O(nmlogm)
O(nmlogm)。
upd at 20.05.27: 用FWT DP的时候每次不用IFWT和FWT,初值直接用定义
(
−
1
)
i
&
j
(-1)^{i\&j}
(−1)i&j,然后给儿子的FWT每个位置+1,这样DP过程就没有log了,在DP完之后IFWT一下,复杂度是
O
(
n
m
+
m
l
o
g
m
)
O(nm+mlogm)
O(nm+mlogm)的。
连通块DP更通用的解法是先点分治,然后求出包含点分中心的连通块的答案。
按照dfs序从后往前进行DP,如果一个点不选,那么它的子树也不能选,即在dfs序上跳到子树外。
f
[
i
]
[
j
]
=
f
[
i
+
1
]
[
j
x
o
r
a
[
i
]
]
+
f
[
i
+
s
i
z
[
i
]
]
[
j
]
f[i][j]=f[i+1][j ~xor~a[i]]+f[i+siz[i]][j]
f[i][j]=f[i+1][j xor a[i]]+f[i+siz[i]][j]。复杂度
O
(
n
m
l
o
g
n
)
O(nmlogn)
O(nmlogn)
Code:
#include<bits/stdc++.h>
#define maxn 1005
using namespace std;
const int mod = 1e9+7;
int T,n,k,a[maxn],siz[maxn],dfn[maxn],tim,ln[maxn],f[maxn][1<<10],ans[1<<10];
bool vis[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
void getroot(int u,int ff,int tsz,int &g){
siz[u]=1; bool flg=1;
for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=ff)
getroot(v,u,tsz,g),siz[u]+=siz[v],flg&=siz[v]<<1<=tsz;
if(flg&&(tsz-siz[u])<<1<=tsz) g=u;
}
void dfs(int u,int ff){
ln[dfn[u]=++tim]=u,siz[u]=1;
for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=ff) dfs(v,u),siz[u]+=siz[v];
}
inline int add(int x,int y){return (x+=y)>=mod?x-mod:x;}
void TDC(int u,int tsz){
getroot(u,0,tsz,u),vis[u]=1;
tim=0,dfs(u,0);
memset(f[siz[u]+1],0,k<<2),f[siz[u]+1][0]=1;
for(int i=siz[u];i>=2;i--)
for(int j=0;j<k;j++)
f[i][j]=add(f[i+1][j^a[ln[i]]],f[i+siz[ln[i]]][j]);
for(int i=0;i<k;i++) ans[i]=add(ans[i],f[2][i^a[u]]);
for(int i=fir[u],v;i;i=nxt[i]) if(!vis[v=to[i]]) TDC(v,siz[v]);
}
int main()
{
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
memset(fir,0,(n+1)<<2),tot=0,memset(vis,0,n+1);
for(int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),line(x,y),line(y,x);
memset(ans,0,k<<2),TDC(1,n);
for(int i=0;i<k;i++) printf("%d%c",ans[i],i==k-1?10:32);
}
}