Description
给定一棵 N 个节点的树, 每个点 i 有权值 a[i] , 1 <= a[i] <= M . 有 Q 个询问, 对于询问 x,y,k , 分别输出树上从 x 到 y 的路径中, 权值小于/等于/大于 k 的点的数目.
Solution
恩。。权值线段树?还要判断区间,好吧上主席树咯。如果不在树上,那么查询[l,r]关于小于k的数目。我们对区间建立线段树,可持久化权值(不知道能不能这么表述)。反正就是建立[1,n]的线段树,从小到大插入权值,比如tree[m]表示已经把小于等于m的权值的点插入到树中了,而主席树是可减的,那么问题就解决了。答案就是
query(Tree: tree[k]-tree[0], Range: [l, r])
拿到树上了呢?可能最容易想到的就是树链剖分了,简单实现一下,可能会爆栈,要用bfs。时间复杂度是
O(Qlog2N)
,是否有优化空间?有,考虑到我们查询树链只想知道满足小于k的数目而不关心到底怎么个小于,即顺序,而且树链是可加的。所以我们用LCA解决即可。对每个点建立权值线段树,那么查询树链[x,y]就变成了:[root,x]+[root,y]-2*[root,lca(x,y)]。时间复杂度变为
O(QlogN)
只有一个树链剖分的。。。。。
#include <cstdio>
#include <algorithm>
#include <ctime>
using namespace std;
const int N = 262190, M = 131080;
int read() {
int s = 0, f = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
struct Seg {
Seg *lc, *rc;
int s;
Seg() { lc = rc = this; s = 0; }
Seg(Seg *_l, Seg *_r, int _s) : lc(_l), rc(_r), s(_s) {}
void *operator new(size_t) {
static Seg pool[M * 60], *C = pool;
return C++;
}
Seg *put(int l, int r, int pos) {
int mid = l + r >> 1;
if (l == r) return new Seg(lc, rc, s + 1);
else if (pos <= mid) return new Seg(lc->put(l, mid, pos), rc, s + 1);
else return new Seg(lc, rc->put(mid + 1, r, pos), s + 1);
}
static int get(Seg *s1, Seg *s2, int l, int r, int ql, int qr) {
int mid = l + r >> 1;
if (ql == l && qr == r) return s1->s - s2->s;
if (mid < ql) return get(s1->rc, s2->rc, mid + 1, r, ql, qr);
else if (qr <= mid) return get(s1->lc, s2->lc, l, mid, ql, qr);
else return get(s1->rc, s2->rc, mid + 1, r, mid + 1, qr) + get(s1->lc, s2->lc, l, mid, ql, mid);
}
} *tree[M];
pair<int, int> a[N];
int h[N], p[N * 2], v[N * 2], cnt = 0, id = 0, n;
int pos[N], top[N], son[N], fa[N], dep[N], sz[N];
void add(int x, int y) {
p[++cnt] = h[x]; v[cnt] = y; h[x] = cnt;
p[++cnt] = h[y]; v[cnt] = x; h[y] = cnt;
}
void dfs(int x) {
son[x] = 0; sz[x] = 1;
for (int i = h[x]; i; i = p[i])
if (v[i] != fa[x]) {
fa[v[i]] = x; dep[v[i]] = dep[x] + 1;
dfs(v[i]); sz[x] += sz[v[i]];
if (sz[son[x]] < sz[v[i]]) son[x] = v[i];
}
}
void dfs2(int x, int t) {
top[x] = t; pos[x] = ++id;
if (son[x]) dfs2(son[x], t);
for (int i = h[x]; i; i = p[i])
if (v[i] != son[x] && v[i] != fa[x])
dfs2(v[i], v[i]);
}
/*
int q[N];
void bfs() {
int x, f = 0, r = 0;
q[r++] = 1;
while (f < r) {
x = q[f++];
dep[x] = dep[fa[x]] + 1;
sz[x] = 1;
for(int i = h[x]; i; i = p[i])
if (v[i] != fa[x])
fa[v[i]] = x, q[r++] = v[i];
}
for (; f >= 2; f--) {
x = q[f - 1];
sz[fa[x]] += sz[x];
if(sz[x] > sz[son[fa[x]]]) son[fa[x]] = x;
}
for(f = 1; f <= r; f++) {
x = q[f];
if (son[fa[x]] != x) top[x] = x;
else top[x] = top[fa[x]];
}
}
*/
int query(int x, int y, int upper, int lower) {
int fx = top[x], fy = top[y], ans = 0;
while (fx != fy) {
if (dep[fx] < dep[fy]) swap(fx, fy), swap(x, y);
ans += Seg::get(tree[upper], tree[lower], 1, n, pos[fx], pos[x]);
x = fa[fx], fx = top[x];
}
if (dep[x] > dep[y]) swap(x, y);
return ans + Seg::get(tree[upper], tree[lower], 1, n, pos[x], pos[y]);
}
int main() {
int m, q, i, x, y, k, q1, q2, q3;
n = read(), m = read(), q = read();
int lastans = 0;
for (i = 1; i <= n; i++) a[i].first = read();
for (i = 1; i < n; i++) add(read(), read());
dfs(1); dfs2(1, 0);
//bfs();
for (i = 1; i <= n; i++) a[i].second = pos[i];
sort(a + 1, a + n + 1);
tree[0] = new Seg();
for (i = 1; i <= n; i++) tree[a[i].first] = tree[a[i - 1].first]->put(1, n, a[i].second);
for (i = 0; i <= m; i++) if (tree[i] == NULL) tree[i] = tree[i - 1];
while (q--) {
x = read() ^ lastans, y = read() ^ lastans, k = read() ^ lastans;
q1 = query(x, y, k - 1, 0); q2 = query(x, y, k, k - 1); q3 = query(x, y, m, k);
printf("%d %d %d\n", q1, q2, q3);
lastans = q1 ^ q2 ^ q3;
}
return 0;
}