[SPOJ-COT]Count on a tree
Posted gavinzheng
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SPOJ-COT]Count on a tree相关的知识,希望对你有一定的参考价值。
[SPOJ-COT]Count on a tree
题面
You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight.
We will ask you to perform the following operation:
- u v k : ask for the kth minimum weight on the path from node u to node v
Input
In the first line there are two integers N and M. (N, M <= 100000)
In the second line there are N integers. The ith integer denotes the weight of the ith node.
In the next N-1 lines, each line contains two integers u v, which describes an edge (u, v).
In the next M lines, each line contains three integers u v k, which means an operation asking for the kth minimum weight on the path from node u to node v.
Output
For each operation, print its result.
Example
Input:
8 5
105 2 9 3 8 5 7 7
1 2
1 3
1 4
3 5
3 6
3 7
4 8
2 5 1
2 5 2
2 5 3
2 5 4
7 8 2
Output:
2
8
9
105
7
思路
这是一个把主席树推广到树上的题。我们首先思考一下,普通的主席树/权值线段树只能对线性的区间进行操作,我们要做的,就是把一棵树分解成一个线性的结构,同时便于进行题目规定的查询操作。
因为这道题是求路径到LCA上的k小值。我们就可以把每个节点到根节点的路径建一棵树。每个节点的子节点对应的线段树可以从父节点线段树继承得到。复杂度\(n\log_2 n\)。
那解法就很显然了,我们先对根节点建一个权值线段树,然后按照DFS序依次遍历整棵树,将父节点继承下来,成为一颗新的树。
对于查询\((i,j,k)\),我们只需要求出一棵包含\(i\)到\(j\)所有点权值的权值线段树,按照k小值标准查询方式查询即可。
那么我们设这棵线段树为\(T_a\),从节点\(i\)到根节点的权值线段树为\(T_i\)。那么很显然:
\[
T_a=T_i+T_j-T_{LCA(i,j)}-T_{fa[LCA(i,j)]}
\]
注意,至于为什么最后一项是\(fa[LCA(i,j)]\),仔细想一想就能发现如果两个都是\(LCA(i,j)\),会把\(LCA(i,j)\)多减一次。
代码
以上是关于[SPOJ-COT]Count on a tree的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ-2588Count on a tree 主席树 + 倍增