题目出处
这道题目出自hackerrank的8月月赛的第三题。
题目大意:
先给出一棵树
之后有三种操作分别为:加边,查询,和删除一个节点
查询的时候要给出任意节点x的第k个祖先
每组数据有t个case
每个case边(P)的数量小于等于10^5
每个case的操作的数量(Q)小于等于10^5
题目分析:
一开始拿到这个题目的时候被搞得一头雾水,如果采用普通的暴力的办法,每一个查询需要O(P),总体的复杂度就变成了O(Q*P),铁定TLE…
思考了三天没有什么想法然后搜了一下,发现了这个:
Level ancestor problem
研读了一番之后发现了使用一个神奇的数据结构,使得每一次的查询可以降为long(P)的复杂度,这样问题就迎刃而解了。
这个奇特的数据结构,我这样描述:
对树进行DFS,记录下每一条路径e[i]。
之后开一个node[i]标记每个节点所在的边号(index),以及在该边的深度(depth)还有该点的“父节点”(father 该点所在边的起点e[node[i].index][0]的父节点)。
那么查询的时候Q(x,k)就等于:
k <= node[x].depth 时 return e[node[x].index][node[x].depth-k]
k > node[x].depth 时 return Q(node[x].father,k-1)
之后就是一系列的边界描述,不再赘述了。
第一次写出来的这个代码十分之丑陋,大家见笑了
python3写的
Level ancestorclass node: def __init__(self,depth = 0,father = -1,index = -1,mark = -2): self.depth = depth self.father = father self.index = index self.mark = mark path = [] nodes = [] MAXN = 100000+5 def NEW(x,y): path.append([y,x]) l = len(path)-1 nodes[y] = node(0,-1,l,-1) nodes[x] = node(0,y,l,1) def CON(x,y): if ( nodes[y].mark == 1 ): nodes[x] = node(nodes[y].depth+1,nodes[y].father,nodes[y].index,1) nodes[y].mark = 0 path[nodes[y].index].append(x) elif(( nodes[y].mark == -1 ) & ( len(path[nodes[y].index]) == 1 ) ): nodes[x] = node(nodes[y].depth+1,nodes[y].father,nodes[y].index,1) path[nodes[y].index].append(x) else: ADD(x) l = len(path)-1 nodes[x] = node(0,y,l,1) def ADD(x): path.append([x]) def update(x,y): if ( ( nodes[x].mark == -2 ) & ( nodes[y].mark == -2 ) ): NEW(x,y) elif ( ( nodes[x].mark == -2 ) & ( nodes[y].mark != -2 ) ): CON(x,y) elif ( ( nodes[x].mark != -2 ) & ( nodes[y].mark != -2 ) ): nodes[x].father = y elif ( ( nodes[x].mark != -2 ) & ( nodes[y].mark == -2 ) ): ADD(y) nodes[y] = node(0,-1,len(path)-1,1) nodes[x].father = y def DEL(x): path[nodes[x].index].remove(x) nodes[x] = node() def LOA(x,k): if ( x == 0 ): return 0; if ( nodes[x].mark == -2 ): return 0 if (nodes[x].depth >= k): lt = nodes[x].depth - k if ( path[nodes[x].index][0] == 0 ): lt = lt+1 return path[nodes[x].index][lt] if ( nodes[x].depth < k ): if ( ( nodes[x].father == -1 ) or ( nodes[x].father == 0 ) ): return 0 t = LOA(nodes[x].father,k-nodes[x].depth-1) return t def INIT(): global path global nodes path = [] nodes = [node() for i in range(0,MAXN)] def build(): n = int(input()) for i in range(0,n): x,y = input().split(' ') x = int(x) y = int(y) update(x,y) #print(path) def Q(): n = int(input()) for i in range(0,n): lt = input().split(' ') if ( lt[0] == '0' ): update(int(lt[2]),int(lt[1])) #print(path) if ( lt[0] == '1' ): DEL(int(lt[1])) if ( lt[0] == '2' ): print(LOA(int(lt[1]),int(lt[2]))) t = input() t = int(t) for i in range(0,t): INIT() build() Q()
以后争取做到学会了就记录下来,这个代码贴给后人鄙视吧