首先给出定义
点分治
是一种处理树上路径的工具
1 #include <iostream> 2 #include <cstring> 3 #include <vector> 4 #include <bitset> 5 6 const int MAXN=3e3+5; 7 const int MAXM=1e5+5; 8 9 int E[MAXN][MAXN]; 10 int all[MAXN]; 11 12 int f[MAXN],son[MAXN],root,tot; 13 /* 14 分别代表f[x]的两侧孩子数目的最大值,重心的孩子数目最小 15 son代表以x为根的孩子数目 16 root是被移动的根 17 tot是当前根的孩子总数 18 */ 19 bool vis[MAXN]; 20 21 std::bitset<MAXM>b[MAXN],ans; 22 23 int n,m,val[MAXN]; 24 25 void dfs(int x,int fa){ 26 /* dfs搜索树,将根移动到树的重心,降低dp层数 */ 27 f[x] = 0; 28 /* 标记孩子数目为0 */ 29 son[x] = 1; 30 /* 计算孩子数目 */ 31 for(int i = 1; i <= all[x]; i++) 32 { 33 int y=E[x][i]; 34 if(!vis[y] && y!=fa) 35 { 36 dfs(y,x); 37 /* 递归进入子数 */ 38 f[x] = std::max(f[x],son[y]); 39 /* 计算子树中孩子数目最多的子树孩子数 */ 40 son[x]+=son[y]; 41 /* 累加孩子数目 */ 42 } 43 } 44 f[x]=std::max(f[x],tot-f[x]); 45 /* 计算该根节点最大孩子数其余侧的数目中两边的最大值 */ 46 if(f[x]<f[root]) root=x; 47 /* 移动根节点,寻找重心 */ 48 } 49 50 void getdp(int x, int fa){ 51 b[x]<<=val[x]; 52 /* 累加val[x] */ 53 son[x]=1; 54 55 56 for(int i=1;i<=all[x];i++) 57 { 58 int y=E[x][i]; 59 if(!vis[y] && y!=fa) 60 { 61 b[y]=b[x]; 62 getdp(y,x); 63 son[x]+=son[y]; 64 b[x]|=b[y]; 65 } 66 } 67 } 68 69 void solve(int x){ 70 vis[x] = true; 71 b[x] = 1; 72 getdp(x,0); 73 /* 以某一点为根进行点分治 */ 74 ans|=b[x]; 75 /* 累加答案 */ 76 77 for(int i=1;i<=all[x];i++) 78 { 79 /* 子树递归进行点分治 */ 80 int y=E[x][i]; 81 if(!vis[y]) 82 { 83 tot = son[y]; 84 root = 0; 85 dfs(y,x); 86 /* 先寻找树根 */ 87 solve(root); 88 /* 递归分治 */ 89 } 90 } 91 } 92 93 int main(){ 94 int T; 95 std::cin>>T; 96 while(T--) 97 { 98 scanf("%d%d",&n,&m); 99 for(int i=1;i<=n;i++) all[i]=0; 100 ans.reset(); 101 memset(vis,0,sizeof(vis)); 102 for(int i=1;i<n;i++) 103 { 104 int x,y; 105 scanf("%d%d",&x,&y); 106 E[x][++all[x]]=y; 107 E[y][++all[y]]=x; 108 } 109 for(int i=1;i<=n;i++) 110 { 111 scanf("%d",&val[i]); 112 } 113 114 f[0] = n+5; 115 tot=n; 116 dfs(1,root); 117 solve(root); 118 for(int i=1;i<=m;i++) 119 { 120 printf("%d",(int)ans[i]); 121 } 122 puts(""); 123 } 124 return 0; 125 }