看上去比较像点分治的裸题,因此也考虑通过根节点的子图和不通过根节点的子图。
我们要维护的是,如何做到做完一个儿子后,另一个儿子可以使用前面的信息,这里可以使用bitset,题目只给了3000个点其实也提示了这一点
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e5+10; const int mod=1e7+7; int n,idx; int h[N],ne[N],e[N],w[N]; int cnt[N],vis[N],d[N],sz[N]; int dis[N]; int st[N]; int root; int m; bitset<100010> bit[3030],ans; void add(int a,int b){ e[idx]=b,ne[idx]=h[a],h[a]=idx++; } void dfs_root(int u,int fa,int tot){ int i; sz[u]=1; int ans=0; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||vis[j]) continue; dfs_root(j,u,tot); sz[u]+=sz[j]; ans=max(ans,sz[j]); } ans=max(ans,tot-sz[u]); if(ans*2<=tot){ root=u; } } void dfs_sz(int u,int fa){ sz[u]=1; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||vis[j]) continue; dfs_sz(j,u); sz[u]+=sz[j]; } } void get(int u,int fa){ bit[u]<<=w[u]; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||vis[j]) continue; bit[j]=bit[u]; get(j,u); bit[u]|=bit[j]; } } void work(int u,int tot){ dfs_root(u,-1,tot); u=root; vis[u]=1; dfs_sz(u,-1); bit[u].reset(); bit[u].set(0); get(u,-1); ans|=bit[u]; for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(vis[j]) continue; work(j,sz[j]); } } int main(){ //ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n; scanf("%d%d",&n,&m); int i; ans.reset(); idx=0; for(i=0;i<=n;i++){ h[i]=-1; vis[i]=0; } for(i=1;i<n;i++){ int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } for(i=1;i<=n;i++) scanf("%d",&w[i]); work(1,n); for(i=1;i<=m;i++){ printf("%d",(int)ans[i]); } printf(" "); } return 0; }