題目鏈接
\(Description\)
給定一棵樹,每個點有權值,在\([0,m-1]\)之間。求異或和為\(0,1,...,m-1\)的非空連通塊各有多少個。
\(n\leq 1000,m\leq 2^{10}\)。
\(Solution\)
在每個連通塊的根節點處統計。\(f[x][k]\)表示以\(x\)為根,異或和為\(k\)的連通塊(子樹)有多少個。
那么\(f[x][k]=f[x][k]+\sum_{i\ \mathbb{xor}\ j=k}f[x][i]*f[v][j],\ v=son[x]\)。
后一部分就是異或卷積,可以用\(FWT\)優化。
具體實現,不需要每次轉移一棵子樹都\(FWT,IFWT\)一次。中間過程一直用\(FWT\)后的\(f\)計算就可以了。
可能有的問題是,\(f\)本身(\(f[x][k]\))還要加上自己,必須在轉移的時候\(IFWT\)回去?不妨在\(f[v]\)計算完之后\(IFWT(f[v])\),令\(f[v][0]++\),然后再\(FWT\)回去,用這個\(f[v]\)去更新\(f[x]\)。這樣就可以直接用\(FWT\)后的\(f\)計算了。
\(f[x][0]\)在計算前是不能\(+1\)的,因為必須要求\(f[x]\)代表的非空連通塊是以\(x\)為根的。
最后把所有\(f[i]\ IFWT\)回去,再令\(f[i][0]\)--。
復雜度\(O(nm\log m)\)。
所以有這兩種寫法的差異。。
https://www.cnblogs.com/cjyyb/p/9065611.html
https://blog.csdn.net/clover_hxy/article/details/72722352
還可以點分治。。在第二篇里有。不想寫了。
//858MS 5528K(怎么那么多跑的很快的啊--點分?)
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 200000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
#define inv2 500000004
#define mod 1000000007
#define Add(x,y) (x+y>=mod?x+y-mod:x+y)
#define Sub(x,y) (x<y?x-y+mod:x-y)
typedef long long LL;
const int N=1024+5;int lim,Enum,H[N],nxt[N<<1],to[N<<1],f[1005][N];
char IN[MAXIN],*SS=IN,*TT=IN;inline int read()
{int now=0;register char c=gc();for(;!isdigit(c);c=gc());for(;isdigit(c);now=now*10+c-'0',c=gc());return now;
}
inline void AE(int u,int v)
{to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
void FWT(int *a,int lim,int opt)
{for(int i=2; i<=lim; i<<=1)for(int j=0,mid=i>>1; j<lim; j+=i)for(int k=j; k<j+mid; ++k){int x=a[k], y=a[k+mid];a[k]=Add(x,y), a[k+mid]=Sub(x,y);if(opt==-1) a[k]=1ll*a[k]*inv2%mod, a[k+mid]=1ll*a[k+mid]*inv2%mod;}
}
void DFS(int x,int fa)
{FWT(f[x],lim,1);for(int i=H[x],v; i; i=nxt[i])if((v=to[i])!=fa){DFS(v,x);for(int j=0; j<lim; ++j) f[x][j]=1ll*f[x][j]*f[v][j]%mod;}FWT(f[x],lim,-1), f[x][0]=Add(f[x][0],1), FWT(f[x],lim,1);
}int main()
{static LL Ans[N];for(int T=read(); T--; ){Enum=0, memset(H,0,sizeof H);memset(f,0,sizeof f), memset(Ans,0,sizeof Ans);int n=read(),m=read(); lim=m;for(int i=1; i<=n; ++i) ++f[i][read()];for(int i=1; i<n; ++i) AE(read(),read());DFS(1,1);for(int i=1; i<=n; ++i){FWT(f[i],lim,-1), f[i][0]=Sub(f[i][0],1);for(int j=0; j<m; ++j) Ans[j]+=f[i][j];}for(int i=0; i<m; ++i) printf("%d%c",int(Ans[i]%mod)," \n"[i+1==m]);//輸出格式。。}return 0;
}
轉載于:https://www.cnblogs.com/SovietPower/p/10027062.html
總結
以上是生活随笔為你收集整理的HDU.5909.Tree Cutting(树形DP FWT/点分治)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。