E. Wooden Game
You are given a forest of $k$ rooted trees$^{\text{∗}}$. Lumberjack Timofey wants to cut down the entire forest by applying the following operation:
- Select a subtree$^{\text{†}}$ of any vertex of one of the trees and remove it from the tree.
Timofey loves bitwise operations, so he wants the bitwise OR of the sizes of the subtrees he removed to be maximum. Help him and find the maximum result he can obtain.
$^{\text{∗}}$ A tree is a connected graph without cycles, loops, or multiple edges. In a rooted tree, a selected vertex is called a root. A forest is a collection of one or more trees.
$^{\text{†}}$ The subtree of a vertex $v$ is the set of vertices for which $v$ lies on the shortest path from this vertex to the root, including $v$ itself.
Input
Each test consists of multiple test cases. The first line contains an integer $t$ ($1 \leq t \leq 10^4$) — the number of test cases. Then follows the description of the test cases.
The first line of each test case contains a single integer $k$ ($1 \leq k \leq 10^6$) — the number of trees in the forest.
This is followed by a description of each of the $k$ trees:
The first line contains a single integer $n$ ($1 \leq n \leq 10^6$) — the size of the tree. The vertices of the tree are numbered with integers from $1$ to $n$. The root of the tree is vertex number $1$.
The second line contains $n - 1$ integers $p_2, p_3, \ldots p_n$ ($1 \leq p_i < i$), where $p_i$ — the parent of vertex $i$.
It is guaranteed that the sum of $k$ and $n$ for all sets of input data does not exceed $10^6$.
Output
For each test case, output a single integer — the maximum result that can be obtained.
Example
input
3
1
1
2
4
1 2 2
6
1 1 3 1 3
1
10
1 2 2 1 1 5 7 6 4
output
1
7
10
Note
In the second test case, the trees look like this:
The first operation removes the entire second tree.
The second operation removes vertex $4$ from the first tree.
The third operation removes the first tree. The result is $6|1|3 = 7$ ($|$ denotes bitwise OR).
In the third test case, the entire tree needs to be removed.
解题思路
假设只有一棵树,那么 OR 的最大值就是这棵树本身的大小 $n$。假设把一棵树拆分成了 $m$ 个部分,每个部分的大小为 $a_i$,有 $a_1 \mid a_2 \mid \cdots \mid a_m \leq a_1 + a_2 + \cdots + a_n = n$,这是因为 OR 运算没有进位。另外,对于一棵大小为 $n$ 的树,我们可以拆分得到大小在 $1 \sim n$ 的任意一棵树,每次只需删除叶子即可。因此如果我们想让某棵树贡献某个值时,只需通过删除叶子来得到该大小的树即可,而无需考虑如何拆分。
因此现在的问题变成了,有 $k$ 个数,每个数可取的范围是 $[1, n_i]$,求这 $k$ 个数 OR 的最大值。
从高位往低位贪心考虑,对于某个位 $i$,如果至少有两个数的第 $i$ 位是 $1$,则将其中一个数变小,使其第 $0$ 到第 $i-1$ 位变成 $1$,这样通过 OR 就可以对答案贡献 $2^{i+1} - 1$。如果只有一个数的第 $i$ 位是 $1$,则保留这一位,对答案贡献 $2^i$。
AC 代码如下,时间复杂度为 $O(n \log{n})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5;
int a[N];
void solve() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", a + i);
for (int j = 0; j < a[i] - 1; j++) {
scanf("%*d");
}
}
sort(a, a + n, greater<int>());
int ret = 0;
for (int i = 0; i < n; i++) {
for (int j = 19; j >= 0; j--) {
if (a[i] >> j & 1) {
if (ret >> j & 1) ret |= (1 << j) - 1;
else ret |= 1 << j;
}
}
}
printf("%d\n", ret);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round 959 sponsored by NEAR (Div. 1 + Div. 2) A~E:https://zhuanlan.zhihu.com/p/709662276
标签:int,Wooden,vertex,tree,trees,leq,Game,test From: https://www.cnblogs.com/onlyblues/p/18313527