772 字
4 分钟
BZOJ 2588 [Spoj 10628] Count on a tree
Description
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
Input
第一行两个整数N,M。 第二行有N个整数,其中第i个整数表示点i的权值。 后面N-1行每行两个整数(x,y),表示点x到点y有一条边。 最后M行每行两个整数(u,v,k),表示一组询问。
Output
M行,表示每个询问的答案。最后一个询问不输出换行符
Sample 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
0 5 2
10 5 3
11 5 4
110 8 2
Sample Output
2
8
9
105
7
题解
简单来说可以每个节点复制他父亲的节点在新版本中插入自己
然后两个点之间的k小值就是a-lca + b-fa[lca];
#include <cstdio>#include <queue>#include <climits>#include <algorithm>using namespace std;struct Seg_Node *null;struct Seg_Node{ Seg_Node *ch[2]; int cnt; //#define cnt(_) ((_) ? (_)->cnt : 0) Seg_Node(Seg_Node *l, Seg_Node *r) { ch[0] = l, ch[1] = r; cnt = ch[0]->cnt + ch[1]->cnt; } Seg_Node(Seg_Node *l, Seg_Node *r, int _cnt) { ch[0] = l, ch[1] = r; cnt = _cnt; } Seg_Node *insert(int l, int r, int x) { if (l == r) return new Seg_Node(null, null, cnt + 1); else { int m = l + (r - l) / 2; if (x <= m) return new Seg_Node(ch[0]->insert(l, m, x), ch[1]); else return new Seg_Node(ch[0], ch[1]->insert(m + 1, r, x)); } }};struct Node{ vector<Node *> ch; Node *fa; int dep, w; bool vis; Seg_Node *Seg;} v[100005];
void addedge(int a, int b){ v[a].ch.push_back(&v[b]); v[b].ch.push_back(&v[a]);}void init(){ null = new Seg_Node(NULL, NULL, 0); null->ch[0] = null->ch[1] = null;}int n, f[100005][20], logn;void build(){ v[0].vis = 1; v[0].Seg = null; queue<Node *> Q; Q.push(&v[1]); v[1].vis = 1; v[1].dep = 1; v[1].fa = &v[0]; while (!Q.empty()) { Node *e = Q.front(); Q.pop(); e->Seg = e->fa->Seg->insert(0, INT_MAX, e->w); for (Node **p = &e->ch.front(), *u = *p; p <= &e->ch.back(); u = *++p) { if (!u->vis) { u->vis = 1; u->dep = e->dep + 1; u->fa = e; Q.push(u); } } } while ((1 << (logn + 1)) <= n) logn++; f[1][0] = 1; for (int i = 2; i <= n; i++) f[i][0] = v[i].fa - v; for (int j = 1; j <= logn; j++) { for (int i = 1; i <= n; i++) { f[i][j] = f[f[i][j - 1]][j - 1]; } }}int lca(int s, int e){ if (v[s].dep < v[e].dep) swap(s, e); if (v[s].dep > v[e].dep) { for (int i = logn; i >= 0; i--) { if (v[f[s][i]].dep >= v[e].dep) s = f[s][i]; } } if (s != e) { for (int i = logn; i >= 0; i--) { if (f[s][i] != f[e][i]) { s = f[s][i]; e = f[e][i]; } } return f[s][0]; } return s;}int Query(int s, int e, int k){ int p = lca(s, e); Seg_Node *Su = v[s].Seg, *Sv = v[e].Seg, *Sp = v[p].Seg, *Sf = v[p].fa->Seg; int l = 0, r = INT_MAX; while (l < r) { int m = l + (r - l) / 2; int S = Su->ch[0]->cnt + Sv->ch[0]->cnt - Sp->ch[0]->cnt - Sf->ch[0]->cnt; if (k > S) { k -= S; l = m + 1; Su = Su->ch[1]; Sv = Sv->ch[1]; Sp = Sp->ch[1]; Sf = Sf->ch[1]; } else { r = m; Su = Su->ch[0]; Sv = Sv->ch[0]; Sp = Sp->ch[0]; Sf = Sf->ch[0]; } } return l;}int main(){ int m; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &v[i].w); for (int i = 1; i <= n - 1; i++) { int s, e; scanf("%d%d", &s, &e); addedge(s, e); } init(); build(); int ans = 0; while (m--) { int s, e, k; scanf("%d%d%d", &s, &e, &k); s ^= ans; printf(m ? "%d\n" : "%d", ans = Query(s, e, k)); }}
BZOJ 2588 [Spoj 10628] Count on a tree
https://www.nekomio.com/posts/56/