会员专享
请先
登录 ,登录后可使用今日免费解锁;
开通会员 后可解锁完整内容。
解题思路
核心思路
一条告警的「同源性」只由它的路径指纹决定:在每棵树上从根出发独立推理,走到叶子即得该树落点编号,T T T 棵树的落点编号依次组成一个 T T T 元组。指纹相同即同源。于是只需对全部 N N N 条告警各做一次推理求出指纹,用哈希表维护每个指纹的两个量——出现次数与最小编号(告警按编号从小到大处理,首见指纹时的编号即最小值)——之后每条查询用查询告警的指纹查表,O ( 1 ) O(1) O ( 1 ) 回答。
指纹的存储:T ≤ 8 T \le 8 T ≤ 8 且 K ≤ 32 K \le 32 K ≤ 32 (落点编号在 1 ∼ 32 1 \sim 32 1 ∼ 32 之间),把每棵树的落点编号作为一个 6 位段依次压入一个 64 位整数:
k e y = ∑ t = 1 T n o d e t ⋅ 64 T − t key = \sum_{t=1}^{T} node_t \cdot 64^{T-t}
k ey = t = 1 ∑ T n o d e t ⋅ 6 4 T − t
题目内容
某云监控平台每天产生海量网络告警,运维团队训练了一个随机森林模型来识别根因告警。模型已离线训练完成,现在需要你实现该模型的推理与同源告警检索引擎 。
随机森林由 T T T 棵独立的决策树组成。每条告警包含 M M M 个特征属性。对每棵树,从根节点开始独立评估:
如果遇到内部节点,会判断告警的第 i d x idx i d x 个特征值是否 ≤ \le ≤ 阈值 v a l val v a l :如果是,则走向左子节点;否则走向右子节点。
如果走到叶子节点,推理结束。定义该告警在这棵树上的落点 为该叶子节点的节点编号。
一条告警的路径指纹 定义为一个 T T T 元组:它在第 1 1 1 棵树到第 T T T 棵树上的落点编号依次组成。指纹只由落点编号决定,与叶子上的标签无关 ——两条告警即使每个落点的标签都相同,只要落点编号不完全一致,就不算同源。
落点编号序列完全相同的告警构成一组同源告警 。运维平台随后收到 Q Q Q 条查询,每条查询给出一个告警编号 j j j ,需要回答:与第 j j j 条告警同源的告警(含第 j j j 条自身)共有多少条,以及这些告警中编号最小的是多少(用于定位该组告警中最早出现的源头)。
注意:查询数量很大,请设计高效的算法在时限内完成所有查询。
解答要求
时间限制:C/C++ 1000ms,其他语言:2000ms
内存限制:C/C++ 512MB,其他语言:1024MB
输入描述
第一行:4 个用空格分隔的整数 T T T M M M N N N Q Q Q 。T T T 为树的数量,M M M 为特征维度数,N N N 为告警条数,Q Q Q 为查询条数。
接下来是 T T T 棵树的结构定义。对于每棵树:
第一行:一个整数 K K K ,表示该树共有 K K K 个节点。节点编号为 1 1 1 到 K K K ,根节点编号固定为 1 1 1 。
接下来 K K K 行,按节点编号 1 ∼ K 1 \sim K 1 ∼ K 的顺序依次描述每个节点。每行以一个整数 t y p e type t y p e 开头:
若 t y p e = 1 type=1 t y p e = 1 ,代表内部节点,后接 4 个整数 i d x idx i d x v a l val v a l l e f t left l e f t r i g h t right r i g h t :若告警的第 i d x idx i d x 个特征值 ≤ v a l \le val ≤ v a l ,跳至编号 l e f t left l e f t 的节点,否则跳至编号 r i g h t right r i g h t 的节点(特征索引 i d x idx i d x 从 1 开始)。
若 t y p e = 0 type=0 t y p e = 0 ,代表叶子节点,后接 1 个整数 l a b e l label l ab e l (0 0 0 或 1 1 1 ),表示该节点的分类结果。
接下来 N N N 行告警数据:每行 M M M 个用空格分隔的整数,代表一条告警的 M M M 个特征值。
最后 Q Q Q 行查询:每行一个整数 j j j 。
约束
1 ≤ T ≤ 8 1 \le T \le 8 1 ≤ T ≤ 8
1 ≤ M ≤ 6 1 \le M \le 6 1 ≤ M ≤ 6
1 ≤ N ≤ 2 × 10 4 1 \le N \le 2 \times 10^4 1 ≤ N ≤ 2 × 1 0 4
1 ≤ Q ≤ 2 × 10 5 1 \le Q \le 2 \times 10^5 1 ≤ Q ≤ 2 × 1 0 5
1 ≤ K ≤ 32 1 \le K \le 32 1 ≤ K ≤ 32
t y p e = 1 type=1 t y p e = 1 时:1 ≤ i d x ≤ M 1 \le idx \le M 1 ≤ i d x ≤ M ,l e f t , r i g h t ∈ [ 1 , K ] left, right \in [1,K] l e f t , r i g h t ∈ [ 1 , K ]
t y p e = 0 type=0 t y p e = 0 时:l a b e l ∈ { 0 , 1 } label \in \{0, 1\} l ab e l ∈ { 0 , 1 }
− 10 9 ≤ v a l -10^9 \le val − 1 0 9 ≤ v a l 且告警特征值 ≤ 10 9 \le 10^9 ≤ 1 0 9
1 ≤ j ≤ N 1 \le j \le N 1 ≤ j ≤ N
题目保证树结构合法:不存在环,每个内部节点的两个子节点编号均有效
输出描述
输出共 Q Q Q 行,按查询给出的顺序,每行输出两个用空格分隔的整数:与该查询同源的告警总数(含自身),以及这些告警中最小的编号。
样例1
输入
2 2 4 3
3
1 1 5 2 3
0 0
0 1
3
1 2 3 2 3
0 1
0 0
3 4
7 2
6 9
9 1
4
2
3
输出
2 2
2 2
1 3
说明
共 2 棵树、4 条告警。逐条推理:
告警 1 [ 3 , 4 ] [3,4] [ 3 , 4 ] :树 1 中 3 ≤ 5 3 \le 5 3 ≤ 5 成立走左到叶子 2;树 2 中第 2 特征 4 ≤ 3 4 \le 3 4 ≤ 3 不成立走右到叶子 3。指纹 ( 2 , 3 ) (2,3) ( 2 , 3 ) 。
告警 2 [ 7 , 2 ] [7,2] [ 7 , 2 ] :树 1 中 7 ≤ 5 7 \le 5 7 ≤ 5 不成立到叶子 3;树 2 中 2 ≤ 3 2 \le 3 2 ≤ 3 成立到叶子 2。指纹 ( 3 , 2 ) (3,2) ( 3 , 2 ) 。
告警 3 [ 6 , 9 ] [6,9] [ 6 , 9 ] :树 1 到叶子 3;树 2 到叶子 3。指纹 ( 3 , 3 ) (3,3) ( 3 , 3 ) 。
告警 4 [ 9 , 1 ] [9,1] [ 9 , 1 ] :树 1 到叶子 3;树 2 到叶子 2。指纹 ( 3 , 2 ) (3,2) ( 3 , 2 ) 。
查询 j = 4 j=4 j = 4 :同源组 { 2 , 4 } \{2,4\} { 2 , 4 } ,共 2 条,最小编号 2。查询 j = 2 j=2 j = 2 与之同指纹,同为 2 2。查询 j = 3 j=3 j = 3 :指纹 ( 3 , 3 ) (3,3) ( 3 , 3 ) 只有告警 3 自身,输出 1 3。
样例2
输入
1 1 3 2
1
0 1
5
-7
5
3
1
输出
3 1
3 1
说明
单棵树且 K = 1 K=1 K = 1 :根节点即为叶子,任何告警的落点都是节点 1,指纹恒为 ( 1 ) (1) ( 1 ) 。三条告警全部同源,共 3 条,最小编号 1。两次查询都输出 3 1。