【百度之星2014~复赛)解题报告】The Query on the Tree

声明

   笔者近期意外的发现 笔者的个人站点 http://tiankonguse.com/ 的非常多文章被其他站点转载,可是转载时未声明文章来源或參考自 http://tiankonguse.com/ 站点,因此,笔者加入此条声明。

    郑重声明:这篇记录《 【百度之星2014~复赛)解题报告】The Query on the Tree》转载自 http://tiankonguse.com/ 的这条记录:http://tiankonguse.com/record/record.php?

id=673


前言

这几天把毕业答辩的事弄完了,于是买票出来玩,结果周六是百度之星的复赛。于是我就没有办法来做比赛了,只是看了看题。目測能够过我两三道题.

今天已经是比赛的第二天了,我还一直没有时间来A掉这些题,今晚抽出时间先把最简单的线段树那道题A了再说.


正文



题意


题目说的非常清楚了,自己看吧.


有一棵树。树的每一个点有点权。每次有三种操作:
  1. Query x 表示查询以x为根的子树的权值和。
  2. Change x y 表示把x点的权值改为y(0<=y<=100)。
  3. Root x 表示把x变为根。


分析


这道题的数据起始非常弱的.

我最初的想法就能够把这道题过掉.


最初的想法


首先对这个树按1为根dfs根优先编号,这个应该没有什么疑问.

编号的优点是一个子树变为了一个连续的区间.

编号的时候保存一下这个子树的编号区间,保存在子树的根上.

编号的时候顺便计算一下子树的权值和.

编号的时候记录一下一个节点的父节点.


改动操作


先说说改动操作,改动某个节点时,就算出这个节点应该添加多少,然后从这个节点開始更新,一直更新到根1.

平均复杂度 O( log(n) )

最坏复杂度 O( n )


设置根


这里我们须要一个变量来表示眼下的根是那个节点,比方使用root变量。默认值是1.

设置根仅仅须要把根变量更新一下就可以.

平均复杂度 O( 1 )

最坏复杂度 O( 1 )


查询操作

查询的时候分三种情况:

1.查询的节点是眼下的根 

这个时候答案显然是整个树的权值和,返回 根1的权值和就可以.


2.眼下的根不是查询的节点的某个子孙(即根不在查询的子树里面)

这个时候,答案和根是1的情况同样,及直接返回查询节点的权值和就可以.

怎么推断根是不是查询节点的子孙呢?

寻常的方法是用 LCA 查询,这里我直接使用子树区间来推断就可以.


3.眼下的根是查询节点的某个子孙.

这个时候,我们想象一下,我们拿起根,查询节点的子孙有那些呢?

即那些会在查询节点的以下呢?

如果查询节点是 x,  x的一个儿子是y, 根是y的一个子孙(也可能是y).

这个时候,我们拿起根,x 应该变成 y 的儿子了吧.

这时树的权值应该是 x 原先的权值和 - y 节点的权值和 + 不在x子树区间的全职和.

然后,我们能够发现 x 原先的权值和 + 不在x子树区间的权值和 = 整个树的权值和.

故终于答案是 整个树的权值和 - y节点的权值和.


问题:怎么找到y节点.

有两个方法:

1.枚举x的儿子来推断

2.从根不断的找父亲来推断.

因为题意没有说最多儿子有多少个,所以第一个方法最坏情况下为 O( n ) (非常多儿子)

相应的,第二个方法最坏情况下也是 O( n ) (树退化为链表).


只是我们不用管最坏情况,先这样实现了再说.


综合操作复杂度:log(n)


线段数优化

首先对于改动操作,线段树优化后能够使最坏情况达到 O( log( n ) ).

对于查询操作。因为须要知道 x 的那个儿子 y, 这个我眼下没有想到 O( log( n ) ) 的方法.

学弟说那仅仅能使用二分了.

可是怎么二分呢?

发现二分不了,只是能够使用随机算法来优化找儿子的效率.

起初我们是遍历x的全部儿子,这里我们随机挑一个儿子来寻找.这也算是一个比較好的优化方法吧.



代码

暴力版代码 https://github.com/tiankonguse/ACM/blob/master/astar/2014/3/2.2.cpp(比較简洁)

线段树优化版代码 https://github.com/tiankonguse/ACM/blob/master/astar/2014/3/2.cpp

对于上面说的几个方法我仅仅实现了两个,其它的都非常easy,有兴趣的朋友能够尝试一下.


參考

http://blog.csdn.net/hongrock/article/details/27839237(这个參考主要用于确认暴力不会超时。假设精心构造数据。这种方法会超时的)

转载于:https://www.cnblogs.com/jzssuanfa/p/6805098.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值