令
fi,j
表示时间为
i
的时候,
那么 fi,u=XOR{fi−1,v|v∈sonu}
fi−1,v 用 fi−1,v′ 带入不断展开
就可以得到 fx,1=XOR{ai∗f0,i} ,其中 ai∗f0,i 表示 ai 个 f0,i 异或起来
手动展开一下发现这个系数就跟这个点的深度有关,可以递推得到
并且 ai 的递推形式就跟组合数的递推形式一样。
推一推就可以知道 ai=(depth+x−2depth−1)
显然当 ai 为奇数的时候,点 i 才有贡献。
考虑lucas定理,也就是说
再转化就是 x−1 与 depth−1 没有重合,也就是and起来为0
然后就 3logn 子集统计一下就好了
x
很大,但是只有
UPD:子集统计可以用高维前缀和,复杂度就降到了 nlogn
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=1000010;
int n,m,cnt,imax,fa[N],dpt[N],G[N];
ll a[N];
struct iedge{
int t,nx;
}E[N<<1];
inline void addedge(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}
int it;
void dfs(int x,int f){
fa[x]=f; dpt[x]=dpt[f]+1;
imax=max(imax,dpt[x]);
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f) dfs(E[i].t,x);
}
inline int C(int x,int y){
if(!x && !y) return 1;
if(!(x&1) && (y&1)) return 0;
return C(x/2,y/2);
}
ll f[N],g[N];
void PutAns(ll x){
if(x>=10) PutAns(x/10); putchar(x%10+'0');
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<n;i++)
scanf("%d%d",&x,&y),addedge(x+1,y+1);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
dfs(1,0);
int NN=1; while(NN<imax) NN<<=1; NN--;
for(int i=1;i<=n;i++) f[dpt[i]-1]^=a[i];
/*for(int i=0;i<=NN;i++){
g[i]^=f[0];
for(int j=NN-i;j;j=(j-1)&(NN-i))
g[i]^=f[j];
}
while(m--){
ll x; scanf("%lld",&x);
if(x==0) PutAns(a[1]);
else PutAns(g[(x-1)%(NN+1)]); putchar('\n');
}*/
for(int i=0;i<=17;i++)
for(int j=0;j<=NN;j++)
if(~j>>i&1) f[j|(1<<i)]^=f[j];
while(m--){
ll x; scanf("%lld",&x);
if(x==0) PutAns(a[1]);
else PutAns(f[NN-(x-1)%(NN+1)]); putchar('\n');
}
}