[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的主要内容,如果未能解决你的问题,请参考以下文章

SPOJ Count on a tree

BZOJ-2588Count on a tree 主席树 + 倍增

[SPOJ10707]Count on a tree II

积累Count on a Tree

BZOJ2588 Spoj 10628. Count on a tree

「luogu2633」Count on a tree