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


Hint







HINT:



N,M<=100000



暴力自重。。。


正解,每个点维护一个可持久化线段树,通过容斥可以知道,链(x,y)等于tree(x)+tree(y)-tree(lca(x,y))-tree(fa[lca(x,y)])

然后就是线段树上求第k小了。注意最后一行不要回车,会格式错误。


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define loop(i,j,k) for (int i=j;i!=-1;i=k[i])
#define inone(x) scanf("%d",&x)
#define intwo(x,y) scanf("%d%d",&x,&y)
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
const int low(int x) { return x&-x; }
const int N = 2e5 + 10;
int n, m, nn, x, y, z;
int ft[N], nt[N], u[N], v[N], a[N], sz;
int ct[N], mx[N], fa[N];
int dep[N], top[N];
int rt[N], L[N * 20], R[N * 20], f[N * 20];

void add(int x, int &y, int l, int r, int u)
{
y = ++sz; L[y] = L[x]; R[y] = R[x]; f[y] = f[x] + 1;
if (l == r) return;
int mid = l + r >> 1;
if (u <= mid) add(L[x], L[y], l, mid, u);
else add(R[x], R[y], mid + 1, r, u);
}

void dfs(int x, int f)
{
add(rt[f], rt[x], 1, nn, v[x]);
ct[x] = 1; mx[x] = 0;
fa[x] = f; dep[x] = dep[f] + 1;
loop(i, ft[x], nt)
{
if (u[i] == f) continue;
dfs(u[i], x);
ct[x] += ct[u[i]];
if (ct[u[i]] > ct[mx[x]]) mx[x] = u[i];
}
}

void Dfs(int x, int t)
{
top[x] = !t ? x : top[fa[x]];
if (mx[x]) Dfs(mx[x], 1);
loop(i, ft[x], nt)
{
if (u[i] == fa[x] || u[i] == mx[x]) continue;
Dfs(u[i], 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] ? y : x;
}

int get(int x, int y, int z)
{
int u = lca(x, y), v = fa[u];
int g[4] = { rt[x],rt[u],rt[y],rt[v] };
for (int l = 1, r = nn; l < r;)
{
int mid = l + r >> 1, res = 0;
for (int i = 0, j = 1; i < 4; i++, j *= -1)
{
res += f[L[g[i]]] * j;
}
if (res >= z)
{
rep(i, 0, 3) g[i] = L[g[i]];
r = mid;
}
else
{
l = mid + 1;
rep(i, 0, 3) g[i] = R[g[i]];
z -= res;
}
if (l == r) return l;
}
}

int main()
{
while (intwo(n, m) != EOF)
{
rep(i, 1, n)
{
inone(v[i]);
a[i] = v[i], ft[i] = -1;
}
sort(a + 1, a + n + 1);
nn = unique(a + 1, a + n + 1) - a - 1;
rep(i, 1, n) v[i] = lower_bound(a + 1, a + nn + 1, v[i]) - a;
rt[0] = L[0] = R[0] = f[0] = ct[0] = dep[0] = sz = 0;
rep(i, 1, n - 1)
{
intwo(x, y);
u[sz] = y; nt[sz] = ft[x]; ft[x] = sz++;
u[sz] = x; nt[sz] = ft[y]; ft[y] = sz++;
}
dfs(1, sz = 0); Dfs(1, 0);
for (int s = 0; m--; )
{
intwo(x, y); inone(z);
x ^= s;
s = a[get(x, y, z)];
printf("%d%s", s, m ? "\n" : "");
}
}
return 0;
}


用树链剖分+二分答案+线段树,效率nlog^4(n)果断超时了,纪念一下。


#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define loop(i,j,k) for (int i=j;i!=-1;i=k[i])
#define inone(x) scanf("%d",&x)
#define intwo(x,y) scanf("%d%d",&x,&y)
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
const int low(int x) { return x&-x; }
const int N = 2e5 + 10;
int n, m, nn, x, y, z;
int ft[N], nt[N], u[N], v[N], sz;
int a[N], b[N];
int ct[N], mx[N], fa[N], to[N], fr[N];
int dep[N], top[N];
int f[20][N];

void dfs(int x, int f)
{
ct[x] = 1; mx[x] = 0;
fa[x] = f; dep[x] = dep[f] + 1;
loop(i, ft[x], nt)
{
if (u[i] == f) continue;
dfs(u[i], x);
ct[x] += ct[u[i]];
if (ct[u[i]] > ct[mx[x]]) mx[x] = u[i];
}
}

void Dfs(int x, int t)
{
top[x] = !t ? x : top[fa[x]];
to[x] = ++sz; fr[sz] = x;
if (mx[x]) Dfs(mx[x], 1);
loop(i, ft[x], nt)
{
if (u[i] == fa[x] || u[i] == mx[x]) continue;
Dfs(u[i], 0);
}
}

void build(int x, int l, int r)
{
if (l == r) { f[x][l] = v[fr[l]]; return; }
int mid = l + r >> 1;
build(x + 1, l, mid); build(x + 1, mid + 1, r);
for (int i = l, j = l, k = mid + 1; i <= r; i++)
{
if (k > r || j <= mid&&f[x + 1][j] <= f[x + 1][k]) f[x][i] = f[x + 1][j++];
else f[x][i] = f[x + 1][k++];
}
}

int get(int x, int l, int r, int ll, int rr, int v)
{
if (ll <= l&&r <= rr) return upper_bound(f[x] + l, f[x] + r + 1, v) - f[x] - l;
int mid = l + r >> 1, res = 0;
if (ll <= mid) res += get(x + 1, l, mid, ll, rr, v);
if (rr > mid) res += get(x + 1, mid + 1, r, ll, rr, v);
return res;
}

int check(int x, int y, int z)
{
int res = 0;
for (; top[x] != top[y]; x = fa[top[x]])
{
if (dep[top[x]] < dep[top[y]]) swap(x, y);
res += get(0, 1, n, to[top[x]], to[x], z);
}
if (dep[x] > dep[y]) swap(x, y);
res += get(0, 1, n, to[x], to[y], z);
return res;
}
int main()
{
while (intwo(n, m) != EOF)
{
rep(i, 1, n)
{
inone(v[i]);
a[i] = v[i], ft[i] = -1;
}
sort(a + 1, a + n + 1);
nn = unique(a + 1, a + n + 1) - a;
rep(i, 1, n) v[i] = lower_bound(a + 1, a + nn, v[i]) - a;
ct[0] = dep[0] = sz = 0;
rep(i, 1, n - 1)
{
intwo(x, y);
u[sz] = y; nt[sz] = ft[x]; ft[x] = sz++;
u[sz] = x; nt[sz] = ft[y]; ft[y] = sz++;
}
dfs(1, 0); Dfs(1, sz = 0); build(0, 1, n);
int s = 0;
while (m--)
{
intwo(x, y); inone(z);
x ^= s;
int q = 1, h = nn, mid;
while (q <= h)
{
mid = q + h >> 1;
if (check(x, y, mid) >= z) h = mid - 1;
else q = mid + 1;
}
printf("%d%s", s = a[q], m ? "\n" : "");
}
}
return 0;
}