题目大意:
就是给你一颗树,树上每个点都有自己的权值,问你这棵树是否存在一棵子树,子树的权值和是 [ 1 , m ] [1,m] [1,m]里面的,对于 [ 1 , m ] [1,m] [1,m]里面的数,如果出现过就输出1,否则就输出0.
解题思路:
1.我选择的思路是点分治。
如何分治呢?因为是联通的子树嘛,那么我对每个分治的节点,我统计出经过这个节点所有子树的答案。
2.如何统计呢?看到答案的01串,我们可以想到bitset去维护结果,因为
n
n
n很小,对于每个
n
n
n我们可以开一个bitset,去维护每个链的
s
u
m
sum
sum,对于出现过的和,我们直接在运用位运算的或,去把相应的位置置
1
1
1;
3.对于某个点肯定是先是继承自己父亲的
b
i
t
[
f
a
]
bit[fa]
bit[fa],然后把这些值加上自己,就进行逻辑左移
v
a
l
_
n
o
d
e
[
u
]
val\_node[u]
val_node[u]位
对于自己孩子节点肯定也要记录下来下面出现了什么值,那么就直接或孩子节点的 b i t [ s o n ] bit[son] bit[son]就可以了,这样答案就已经不重不漏了!
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e3 + 10;
bitset<100010>bit[maxn], ans;
int max_son[maxn], root, siz[maxn];
bool vis[maxn];
vector<int> G[maxn];
int node[maxn];
int n, m, now_node;
//..............................
void out(bitset<100010> a, int u) {
cout << "u:" << u << " " << node[u] <<endl;
for(int i = 1; i <= m; ++ i)
cout << a.test(i);
cout << endl;
}
void getroot(int u, int fa) {
bit[u].reset();
siz[u] = 1;
max_son[u] = 1;
for(auto it : G[u]) {
if(it == fa || vis[it]) continue;
getroot(it,u);
max_son[u] = max(max_son[u],siz[it]);
siz[u] = siz[u] + siz[it];
}
max_son[u] = max(max_son[u],now_node-siz[u]);
if(max_son[u] < max_son[root]) root = u;
}
void getans(int u, int fa) {
bit[u] <<= node[u];//继承了父亲节点的结果后就进行移位
ans |= bit[u];
//out(bit[u],u);
for(auto it : G[u]) {
if(it == fa || vis[it]) continue;
bit[it] = bit[u];//继承父亲的结果
getans(it,u);
bit[u] |= bit[it];//承接儿子的结果
}
//out(bit[u],u);
}
void div(int u) {
vis[u] = true;
bit[u].set(0);//对于分治节点,先把0的位置设置成1,下面就可以直接进行位移
getans(u, 0);
for(auto i : G[u]) {
if(vis[i]) continue;
now_node = siz[i];
root = 0;
getroot(i,u);
div(root);
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
//.........................
int T;
cin >> T;
while(T --) {
ans.reset();
max_son[0] = 1e9;
cin >> n >> m;
for(int i = 1; i <= n; ++ i) {
vis[i] = 0;
G[i].clear();
}
for(int i = 1; i < n; ++ i) {
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
for(int i = 1; i <= n; ++ i) cin >> node[i];
root = 0;
now_node = n;
getroot(1,0);
div(root);
for(int i = 1; i <= m; ++ i)
cout << ans.test(i);
cout << "\n";
}
return 0;
}
/*
1
4 10
1 2
2 3
3 4
3 2 7 5
6 10
1 2
1 3
2 5
3 4
3 6
1 3 5 7 9 11
*/