
Orz..跑得还挺快的#10
自从会树链剖分后LCA就没写过倍增了...
这道题用可持久化线段树..点x的线段树表示ROOT到x的这条路径上的权值线段树
-------------------------------------------------------------------------
#include<bits/stdc++.h>
 
#define rep(i, n) for(int i = 0; i < n; i++)
#define clr(x, c) memset(x, c, sizeof(x))
#define M(l, r) (((l) + (r)) >> 1)
#define foreach(i, x) for(__typeof(x.begin()) i = x.begin(); i != x.end(); i++)
 
using namespace std;
 
const int maxn = 200009;
 
int w[maxn], n, N, id[maxn];
vector<int> G[maxn];
 
namespace LCA {
    int top[maxn], son[maxn], dep[maxn], size[maxn], fa[maxn], TOP;
    
    void dfs(int x) {
	    size[x] = 1; son[x] = -1;
	    foreach(it, G[x]) if(*it != fa[x]) {
		    dep[*it] = dep[x] + 1; 
		    fa[*it] = x;
		    dfs(*it);
		    size[x] += size[*it];
		    if(!~son[x] || size[*it] > size[son[x]])
		        son[x] = *it;
	    }
    }
    void DFS(int x) {
		top[x] = TOP;
		if(~son[x]) DFS(son[x]);
		foreach(it, G[x]) if(*it != son[x] && *it != fa[x])
	    	DFS(TOP = *it);
	}
		    
	void init() {
		dep[0] = 0; fa[0] = -1;
		dfs(0); DFS(TOP = 0);
	}
	
	int LCA(int x, int y) {
		for(; top[x] != top[y]; x = fa[top[x]])
			if(dep[top[x]] < dep[top[y]]) swap(x, y);
		return dep[x] < dep[y] ? x : y;
	}
}
 
struct Node {
	Node *l, *r;
	int s;
} pool[maxn * 40], *pt = pool, *null, *root[maxn];
 
void init() {
	null = pt++; null->s = 0;
	null->l = null->r = null;
}
 
int v;
Node* modify(Node* t, int l, int r) {
	Node* h = pt++;
	h->s = t->s + 1;
	if(r > l) {
		int m = M(l, r);
		if(v <= m) {
			h->l = modify(t->l, l, m);
			h->r = t->r;
		} else {
			h->l = t->l;
			h->r = modify(t->r, m + 1, r);
		}
	}
	return h;
}	
 
void build(int x, int fa = -1, Node* p = null) {
	v = w[x] + 1;
	root[x] = modify(p, 1, N);
	foreach(it, G[x]) if(*it != fa)
	    build(*it, x, root[x]);
}
 
inline int read() {
	char c = getchar();
	int ans = 0, f = 1;
	for(; !isdigit(c); c = getchar())
	    if(c == ‘-‘) f = -1;
	for(; isdigit(c); c = getchar()) 
	    ans = ans * 10 + c - ‘0‘;
	return ans * f;
}
 
int ans = 0;
void work(bool F) {
	int x = (read()^ans) - 1, y = read() - 1, k = read(), lca = LCA::LCA(x, y);
	Node *X = root[x], *Y = root[y], *A = root[lca], *P = lca ? root[LCA::fa[lca]] : null;
	int L = 1, R = N;
	while(L < R) {
		int s = X->l->s + Y->l->s - A->l->s - P->l->s, m = M(L, R);
		if(s >= k) {
			X = X->l; Y = Y->l; A = A->l; P = P->l;
			R = m;
		} else {
			X = X->r; Y = Y->r; A = A->r; P = P->r;
			k -= s;
			L = m + 1;
		}
	}
	ans = id[L - 1];
	printf("%d", ans);
	if(F) putchar(‘\n‘);
}
 
int main() {
	freopen("test.in", "r", stdin);
	
	init();
	n = read();
	int m = read();
	rep(i, n) {
		id[i] = w[i] = read();
	    G[i].clear();
	}
	sort(id, id + n);
	N = unique(id, id + n) - id;
	rep(i, n) w[i] = lower_bound(id, id + N, w[i]) - id;
	rep(i, n - 1) {
		int u = read() - 1, v = read() - 1;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	LCA::init();
	build(0);
	while(m--) work(m);
	
	return 0;
}
------------------------------------------------------------------------- 
2588: Spoj 10628. Count on a tree
Time Limit: 12 Sec  Memory Limit: 128 MB
Submit: 2675  Solved: 606
[Submit][Status][Discuss]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
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 
 
HINT
Source
 
BZOJ 2588: Spoj 10628. Count on a tree( LCA + 主席树 )
原文:http://www.cnblogs.com/JSZX11556/p/4687736.html