1. 程式人生 > >hdu 5909 Tree Cutting——點分治(樹形DP轉為序列DP)

hdu 5909 Tree Cutting——點分治(樹形DP轉為序列DP)

題目:http://acm.hdu.edu.cn/showproblem.php?pid=5909

點分治的話,每次要做一次樹形DP;但時間應該是 siz*m2 的。可以用 FWT 變成 siz*mlogm ,但這裡寫的是把樹變成序列來 DP 的方法,應該是 nlogn*m 的。

樹上的一個點,如果選,就可以選它的孩子,所以它向它的第一個孩子連邊;如果不選,就會跳到它的下一個兄弟或者是父親的下一個兄弟之類的,向那邊連一條邊。

做出樹的 dfs 序,把邊都連在 dfs 序上;其實那個第一條邊一定連向自己 dfs 序+1,即使自己沒有孩子也是符合的,所以可以不用連了;第二條邊可以通過傳父親的連邊物件來解決。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1005,M=1025,mod=1e9+7;
int T,n,m,w[N],hd[N],xnt,to[N<<1],nxt[N<<1],siz[N],rt,mn;
int dfn[N],tot,sta[N],top,f[N][M],g[N],nt[N],ans[M]; bool vis[N];
int rdn()
{
  int ret=0;bool fx=1;char
ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return fx?ret:-ret; } int Mx(int a,int b){return a>b?a:b;} int Mn(int a,int b){return a<b?a:b;} void upd(int &x){x>=mod?x-=mod:0;} void init() { xnt
=0;memset(hd,0,sizeof hd); memset(ans,0,sizeof ans); memset(vis,0,sizeof vis); } void add(int x,int y){to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;} void getrt(int cr,int fa,int s) { siz[cr]=1; int mx=0; for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa) { getrt(v,cr,s);siz[cr]+=siz[v]; mx=Mx(mx,siz[v]); } mx=Mx(mx,s-siz[cr]);if(mx<mn)mn=mx,rt=cr; } void dfs(int cr,int fa) { dfn[cr]=++tot;g[tot]=w[cr]; for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa)dfs(v,cr); } void dfsx(int cr,int fa,int lst) { nt[dfn[cr]]=lst; int l=top+1; for(int i=hd[cr],v;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa)sta[++top]=v; int r=top; for(int i=hd[cr],v,p0=l;i;i=nxt[i]) if(!vis[v=to[i]]&&v!=fa) { dfsx(v,cr,p0==r?lst:dfn[sta[p0+1]]);p0++; } } void solve(int cr,int s) { vis[cr]=1; tot=0;dfs(cr,0);top=0;dfsx(cr,0,s+1); for(int i=1;i<=s+1;i++)memset(f[i],0,sizeof f[i]); f[1][0]=1; for(int i=1;i<=s;i++) for(int j=0;j<m;j++) { if(!f[i][j])continue; f[i+1][j^g[i]]+=f[i][j];upd(f[i+1][j^g[i]]); f[nt[i]][j]+=f[i][j];upd(f[nt[i]][j]); } f[s+1][0]--;//dec the empty for(int j=0,k=s+1;j<m;j++)ans[j]+=f[k][j],upd(ans[j]); for(int i=hd[cr],v,ts;i;i=nxt[i]) if(!vis[v=to[i]]) { ts=(siz[cr]>siz[v]?siz[v]:s-siz[cr]); mn=N;getrt(v,cr,ts);solve(rt,ts); } } int main() { T=rdn(); while(T--) { n=rdn();m=rdn();for(int i=1;i<=n;i++)w[i]=rdn(); init(); for(int i=1,u,v;i<n;i++)u=rdn(),v=rdn(),add(u,v),add(v,u); mn=N;getrt(1,0,n);solve(rt,n); for(int i=0,j=m-1;i<j;i++)printf("%d ",ans[i]); printf("%d\n",ans[m-1]); } return 0; }