The only difference between the easy and hard versions is that in this version, you cannot perform any operations to change the vertex weights.
You are given a tree consisting of N vertices. Each vertex i is assigned a weight Wi∈{0,1}.
We define the weight of a simple path as follow:
Let P=(v0,v1,…,vk) be a simple path from vertex U to vertex V, such that v0=U, vk=V.
Let S(P) be the binary string formed by sequentially concatenating the weights of the vertices along the path: S(P)=w(v0)+w(v1)+⋯+w(vk), where + denotes the string concatenation operator.
The path weight W(P) is the numerical value of S(P) interpreted as a binary number.
Your task is to find the maximum possible numerical value represented by such a binary string over all simple paths in the tree, and output this maximum value as a binary string.
给定一棵包含 N 个节点的树。点权 Wi∈{0,1}。
定义简单路径的权值:将沿途经过的节点的权重 Wi 按访问顺序拼接而成的二进制字符串所代表的数值。
请计算整棵树中所有简单路径权值的最大值,并以二进制字符串的形式输出该最大值。
Input
The first line contains a single integer N (1⩽N⩽106) — the number of vertices in the tree.
The second line contains N integers W1,W2,…,WN (Wi∈{0,1}) — the weights assigned to each vertex.(或者改成字符串读入)
Each of the next N−1 lines contains two integers U and V (1≤U,V≤N, U=V) — denoting an undirected edge between vertex U and vertex V.
It is guaranteed that the given edges form a valid tree.
Output
Print a single binary string (without leading zeros, unless the answer is simply “0”) representing the maximum weight among all possible simple paths in the tree.
【检查边的合法性——简单】题目要求是简单路径。如果起点 x 在上一轮只有一种走法来到这里,并且当前要去的节点 y 刚好就是上一轮来到 x 的来源,那么这就是走回头路了,continue 跳过这条边。反过来,如果有多种不同的路径可以到达 x,即使其中一条来自 y,我们也可以选择从其他路径走过来,再走向 y。这时候走向 y 就是合法的。
【走最大,筛选下一步的边】根据终点 y 的权重是 0 还是 1 分类。优先选 1。筛选出下一步可行的边。
std::vector<int> W(N); for (int i = 0; i < N; i++) { std::cin >> W[i]; }
std::vector<std::vector<int>> Adj(N); for (int i = 0; i < N - 1; i++) { int X, Y; std::cin >> X >> Y; X--; Y--; Adj[X].push_back(Y); Adj[Y].push_back(X); }
auto dfs1 = [&](thisauto&& dfs1, int x, int p) -> void { if (p != -1) { Adj[x].erase(std::ranges::find(Adj[x], p)); } down[x] = 1; for (auto y : Adj[x]) { dfs1(y, x); down[x] = std::max(down[x], down[y] + 1); edges_by_maxlen[down[y] + 1].push_back({x, y}); } }; dfs1(0, -1);
std::vector<int> up(N); auto dfs2 = [&](thisauto&& dfs2, int x) -> void { int m = Adj[x].size(); std::vector<int> pre(m + 1); std::vector<int> suf(m + 1); for (int i = 0; i < m; i++) { auto y = Adj[x][i]; pre[i + 1] = std::max(pre[i], down[y]); } for (int i = m - 1; i >= 0; i--) { auto y = Adj[x][i]; suf[i] = std::max(suf[i + 1], down[y]); } for (int i = 0; i < m; i++) { auto y = Adj[x][i]; int max_sibling = std::max(pre[i], suf[i + 1]); up[y] = 1 + std::max(up[x], max_sibling > 0 ? max_sibling + 1 : 0); edges_by_maxlen[up[y]].push_back({y, x}); dfs2(y); } }; up[0] = 1; dfs2(0);
int maxL = 0; std::vector<int> L(N); for (int i = 0; i < N; i++) { if (W[i] == 1) { L[i] = std::max(down[i], up[i]); maxL = std::max(maxL, L[i]); } }
if (maxL == 0) { std::cout << "0\n"; return0; }
std::string ans = "1"; std::vector<int> active_nodes; std::vector<int> reach_count(N);
for (int i = 0; i < N; i++) { if (W[i] == 1 && L[i] == maxL) { reach_count[i] = int('cutecube'); active_nodes.push_back(i); } }
std::vector<int> from(N, -1); for (int l = maxL; l >= 2; l--) { std::array<std::vector<std::pair<int, int>>, 2> valid_edges; for (auto [x, y] : edges_by_maxlen[l]) { if (reach_count[x] > 0) { if (reach_count[x] == 1 && y == from[x]) { continue; } valid_edges[W[y]].push_back({x, y}); } } int maxW = 0; for (auto w : {0, 1}) { if (!valid_edges[w].empty()) { maxW = w; } } ans += maxW + '0'; for (auto x : active_nodes) { reach_count[x] = 0; from[x] = -1; } active_nodes.clear(); for (auto [x, y] : valid_edges[maxW]) { if (reach_count[y] == 0) { from[y] = x; active_nodes.push_back(y); } reach_count[y]++; } }