一、题目
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
题目链接:http://www.spoj.com/problems/COT/
二、思路
原理其实和一维线性表序列的一样。只不过这是在树上操作。
在一维线性表序列中,扫描序列中每一个离散化后的数字,每一次新建的权值线段树都是基于前一次的。而在树中,对每一个子节点的数字,新建的线段树都是基于父节点的线段树的。
***************************
未完待续……
***************************
三、源代码
#pragma GCC optimize(2) #pragma comment(linker, "/STACK:102400000, 102400000") #include<bits/stdc++.h> using namespace std; typedef long long LL; #define MAXN 111111 LL n, q, m; /*************树部分*******************/ typedef struct { int to, next; } Edge; Edge tree[MAXN * 2]; int head[MAXN], ecnt; void add(int from, int to) { tree[ecnt].to = to; tree[ecnt].next = head[from]; head[from] = ecnt++; } /*************树部分*******************/ /*************LCA部分*******************/ int parent[MAXN][20], depth[MAXN]; void dfs4lca(int r, int par, int d) { parent[r][0] = par, depth[r] = d; for(int i = head[r]; i != -1; i = tree[i].next) { int to = tree[i].to; if(to != par) dfs4lca(to, r, d + 1); } } void init4lca() { dfs4lca(1, -1, 0); for(int k = 0; k < 19; ++k) { for(int v = 1; v <= n; ++v) { if(parent[v][k] < 0) parent[v][k + 1] = -1; else parent[v][k + 1] = parent[parent[v][k]][k]; } } } int lca(int a, int b) { if(depth[a] < depth[b]) swap(a, b); for(int i = 0; i < 20; ++i) { if(((depth[a] - depth[b]) >> i) & 1) a = parent[a][i]; } if(a == b) return a; for(int i = 19; i >= 0; --i) { if(parent[a][i] != parent[b][i]) { a = parent[a][i]; b = parent[b][i]; } } return parent[a][0]; } /*************LCA部分*******************/ /*************主席树部分*******************/ struct { int lch, rch, cnt; } nodes[MAXN * 20]; int root[MAXN], ncnt; void update(int &nroot, int proot, int val, int l = 1, int r = m) { if(!nroot) { nroot = ++ncnt; nodes[nroot].cnt = nodes[proot].cnt + 1; } if(l == r) return; int mid = (l + r) >> 1; if(val <= mid) { nodes[nroot].rch = nodes[proot].rch; update(nodes[nroot].lch, nodes[proot].lch, val, l, mid); } else { nodes[nroot].lch = nodes[proot].lch; update(nodes[nroot].rch, nodes[proot].rch, val, mid + 1, r); } } int query(int uroot, int vroot, int lcaroot, int lcafroot, int k, int l = 1, int r = m) { if(l == r) return l; int cnt = nodes[nodes[uroot].lch].cnt + nodes[nodes[vroot].lch].cnt - nodes[nodes[lcaroot].lch].cnt - nodes[nodes[lcafroot].lch].cnt; int mid = (l + r) >> 1; if(k <= cnt) return query(nodes[uroot].lch, nodes[vroot].lch, nodes[lcaroot].lch, nodes[lcafroot].lch, k, l, mid); else return query(nodes[uroot].rch, nodes[vroot].rch, nodes[lcaroot].rch, nodes[lcafroot].rch, k - cnt, mid + 1, r); } /*************主席树部分*******************/ /*************离散化部分*******************/ LL weight[MAXN], buf[MAXN], mp[MAXN]; int nwt[MAXN]; void discrete() { memcpy(buf + 1, weight + 1, sizeof(weight[0]) * n); sort(buf + 1, buf + n + 1); m = unique(buf + 1, buf + n + 1) - buf - 1; for(int i = 1; i <= n; ++i) { nwt[i] = lower_bound(buf + 1, buf + m + 1, weight[i]) - buf; mp[nwt[i]] = weight[i]; } } /*************离散化部分*******************/ template <class T> inline void read(T &x) { int t; bool flag = false; while((t = getchar()) != '-' && (t < '0' || t > '9')) ; if(t == '-') flag = true, t = getchar(); x = t - '0'; while((t = getchar()) >= '0' && t <= '9') x = x * 10 + t - '0'; if(flag) x = -x; } void init() { memset(head, -1, sizeof(head)); ecnt = 0; //nodes = 0, root = 0, ncnt = 0; } void dfs4tree(int r, int par) { for(int i = head[r]; i != -1; i = tree[i].next) { int to = tree[i].to; if(to != par) { update(root[to], root[r], nwt[to]); dfs4tree(to, r); } } } int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif // ONLINE_JUDGE init(); LL a, b, u, v, k, wt, uvlca, ans; scanf("%lld%lld", &n, &q); for(int i = 1; i <= n; ++i) { read(weight[i]); } for(int i = 1; i < n; ++i) { read(a), read(b); add(a, b); add(b, a); } init4lca(); discrete(); add(0, 1);//添加一条虚边。 dfs4tree(0, -1); while(q--) { read(u), read(v), read(k); uvlca = LL(lca(u, v)); ans = mp[query(root[u], root[v], root[uvlca], root[parent[uvlca][0]], int(k))]; printf("%lld\n", ans); } return 0; }