题目出处

这道题目出自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()

以后争取做到学会了就记录下来,这个代码贴给后人鄙视吧

Kth Ancestor 第k个祖先问题的更多相关文章

  1. Vijos lxhgww的奇思妙想--求K级祖先

    给出一棵树求K级祖先.O(N*logN+Q) 更详细的讲解见:https://www.cnblogs.com/cjyyb/p/9479258.html /* 要求k级祖先,我们可以把k拆成" ...

  2. HDU 4006The kth great number(K大数 +小顶堆)

    The kth great number Time Limit:1000MS     Memory Limit:65768KB     64bit IO Format:%I64d & %I64 ...

  3. K-th Number(第k大数)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 45710   Accepted: 15199 Ca ...

  4. Vijos.lxhgww的奇思妙想(k级祖先 长链剖分)

    题目链接 https://blog.bill.moe/long-chain-subdivision-notes/ http://www.cnblogs.com/zzqsblog/p/6700133.h ...

  5. 树链剖分 (求LCA,第K祖先,轻重链剖分、长链剖分)

      2020/4/30   15:55 树链剖分是一种十分实用的树的方法,用来处理LCA等祖先问题,以及对一棵树上的节点进行批量修改.权值和查询等有奇效. So, what is 树链剖分? 可以简单 ...

  6. Find the largest K numbers from array (找出数组中最大的K个值)

    Recently i was doing some study on algorithms. A classic problem is to find the K largest(smallest) ...

  7. 【POJ2985】【Treap + 并查集】The k-th Largest Group

    Description Newman likes playing with cats. He possesses lots of cats in his home. Because the numbe ...

  8. Kth Smallest Element in a BST 解答

    Question Given a binary search tree, write a function kthSmallest to find the kth smallest element i ...

  9. 4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap

    国际惯例的题面:这种维护排序序列,严格大于的进行操作的题都很套路......我们按照[0,k],(k,2k],(2k,inf)分类讨论一下就好.显然第一个区间的不会变化,第二个区间的会被平移进第一个区 ...

随机推荐

  1. python 自动化之路 day 03

    内容目录: 1. 字典 2. 集合 3. 文件处理 4. 字符编码   1. 字典操作 字典一种key - value 的数据类型,使用就像我们上学用的字典,通过笔划.字母来查对应页的详细内容. 语法 ...

  2. android 开源框架推荐

    同事整理的 android 开源框架,个个都堪称经典.32 个赞! 1.volley 项目地址 https://github.com/smanikandan14/Volley-demo (1)  JS ...

  3. Uniqueidentifier数据类型

    一.Uniqueidentifier数据类型 可存储16字节的二进制值 Uniqueidentifier用来存储一个全局唯一标识符,即GUID.GUID是唯一的二进制数:世界上的任何两台计算机都不会生 ...

  4. php分页笔记

    在做留言板的时候,用到了分页,所以写了这个分页笔记   既然已经开始写分页了,肯定掌握了了php的一些知识以及mysql的基本操作   在做分页的时候,我也遇到了很多问题,但是大家不要怕,无论什么问题 ...

  5. Pyhon编码事项

    1. 永远不要使用import * Pylint代码审查:Wildcard import XXX 如果函数名重名,或者要导入的内容里面包含了from datetime import datetime, ...

  6. Memcached(二)Memcached Java API基础之MemcachedClient

    1. 构造函数 public MemcachedClient(InetSocketAddress[] ia) throws IOException; public MemcachedClient(Li ...

  7. docker下使用caffe的命令记录

    查看所有的images sudo docker images 利用某个image生成container sudo docker run -it --net=host -v /home/tingting ...

  8. Java设计模式之——单例模式

    引自百度百科: 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例类的特殊类. 通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系 ...

  9. ANDROID_MARS学习笔记_S02重置版_001_Hander\Looper\Message\Thread\ThreadLocal

    一. * class LooperThread extends Thread { * public Handler mHandler; * * public void run() { * Looper ...

  10. AD10 gerber生成,及导入cam350 多图详细步骤

    Protel99转Gerber文件导入到CAM350中看为什么钻孔层偏位 这是因为你导入CAM350 时的格式没有设置正确.你用PROTEL 导出钻孔 TXT 时记住是什么格式,例如: 2:3,2:4 ...