Codeforces Round #326 (Div. 1) - C. Duff in the Army 树上倍增算法
题意:一个n个点的数, m个人住在其中的某些点上, 每个人的标号1-m, 询问u-v 路径上标号前a个人,并输出标号,a < 10。
作法, 利用倍增, ID[j][i] 表示i到i的第2^j个祖先上前10个人, 那么每次询问直接维护就好了,细节好多, 刚开始不知道怎么求ID[j][i]。
这里把2^j分成两部分, 前2^(j-1)和 后2^(j-1)个, 然后递推的维护。
感觉树链剖分也可以做, 不知道会不会TLE, 树链剖分的话 线段树的每个点维护10个值, 每次合并就行了。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; const int maxdep = 20; int par[maxdep][maxn], dep[maxn], n; vector <int> ID[maxdep][maxn], cit[maxn]; vector <int> G[maxn]; void init() { for (int i = 0; i < maxn; i++) { G[i].clear(); cit[i].clear(); for (int j = 0; j < maxdep; j++) { ID[j][i].clear(); } } memset(par, -1, sizeof (par)); } void update(vector <int> &v1, vector <int> &v2) { for (int x: v2) { v1.push_back(x); } sort (v1.begin(), v1.end()); v1.erase(unique(v1.begin(), v1.end()), v1.end()); while (v1.size() > 10) { v1.pop_back(); } } void dfs(int u, int father) { par[0][u] = father; dep[u] = dep[father] + 1; for (int i = u; i <= u; i++) { update(ID[0][i], cit[par[0][i]]); update(ID[0][i], cit[i]); for (int j = 0; j + 1< maxdep; j++) { if (~par[j][i]) { par[j+1][i] = par[j][par[j][i]]; update(ID[j+1][i], cit[i]); update(ID[j+1][i], ID[j][i]); update(ID[j+1][i], ID[j][par[j][i]]); } else { par[j+1][i] = -1; } } } for (int v: G[u]) { if (v != father) { dfs(v, u); } } } int lca(int u, int v) { if (dep[u] > dep[v]) { swap(u, v); } for (int k = 0; k < maxdep; k++) { if ((dep[v] - dep[u]) >> k & 1) { v = par[k][v]; } } if (u == v) { return u; } for (int i = maxdep-1; i >= 0; i--) { if (par[i][u] != par[i][v]) { u = par[i][u]; v = par[i][v]; } } return par[0][u]; } int anc; vector <int> solve(int u, int v) { vector <int> res; if (u == v) { update(res, cit[u]); } for (int i = maxdep-1; i >= 0; i--) { if (~par[i][u] && dep[par[i][u]] >= dep[anc]) { update(res, ID[i][u]); u = par[i][u]; } } for (int i = maxdep-1; i >= 0; i--) { if (~par[i][v] && dep[par[i][v]] >= dep[anc]) { update(res, ID[i][v]); v = par[i][v]; } } vector<int> emp; update(res, emp); return res; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int m, q; while (~scanf ("%d%d%d", &n, &m, &q)) { init(); for (int i = 0; i < n-1; i++) { int u, v; scanf ("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } for (int i = 0; i < m; i++) { int c; scanf ("%d", &c); if (cit[c].size() < 10) { cit[c].push_back(i+1); ID[0][c].push_back(i+1); } } dfs(1, 0); while(q--) { int u, v, a; scanf ("%d%d%d", &u, &v, &a); anc = lca(u, v); auto res = solve(u, v); int tot = min((int)res.size(), a); printf("%d%c", tot, " \n"[!tot]); for (int i = 0; i < min((int)res.size(), a); i++) { printf("%d%c", res[i], " \n"[i+1==min((int)res.size(), a)]); } } } return 0; }