题目链接:https://nanti.jisuanke.com/t/17120
题意:给你一棵树,每个点都有权值,q次询问,每次询问给你a,b,k,问从点a到点b每隔k步的异或和是多少。
思路:现场没敢打,复杂度怎么算都不对。。。后来别人说可以1的情况lca其他暴力,我就试了一下,一开始是TLE,然后我各种迷之优化确实可以过。。。。走k步这里我是用了倍增的数组然后用logk的复杂度走k步。。。然后没用memset。。或者加个输入挂我试过也可以过。最后我还有一步没有优化的就是lca没用rmq,直接用的倍增,已经码得够多了不想码rmq了。下面给代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cmath>
#include<queue>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<utility>
#include<set>
#include<map>
#include<stack>
#include<vector>
#define maxn 50005
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long LL;
const double eps = 1e-8;
const int mod = 1e9 + 7;
const int MAXN = 100005;
const int M = 20;
struct node{
int v, value, next;
}p[maxn << 1];
int len, head[maxn], dis[maxn], depth[maxn], n, m, father[maxn][25], a[maxn], b[maxn];
void addedge(int u, int v){
p[len].v = v;
p[len].next = head[u];
head[u] = len++;
}
void dfs(int x, int fa){
father[x][0] = fa;
b[x] = b[fa] ^ a[x];
for (int i = head[x]; ~i; i = p[i].next){
if (p[i].v == fa)
continue;
depth[p[i].v] = depth[x] + 1;
dfs(p[i].v, x);
}
}
void presolve(){
dis[1] = depth[1] = 0;
dfs(1, 0);
for (int i = 1; i < M; i++)
for (int j = 1; j <= n; j++)
father[j][i] = father[father[j][i - 1]][i - 1];
}
int lca(int x, int y){
if (depth[x] != depth[y]){
if (depth[x] > depth[y])
swap(x, y);
int distant = depth[y] - depth[x];
for (int i = 0; i < M; i++){
if (distant&(1 << i))
y = father[y][i];
}
}
if (x == y)
return x;
for (int i = M; i >= 0; i--){
if (father[x][i] != father[y][i]){
x = father[x][i];
y = father[y][i];
}
}
return father[x][0];
}
int find(int x, int k){
int now = x, tmp = 0;
while (k){
if (k & 1)
now = father[now][tmp];
k >>= 1;
tmp++;
}
return now;
}
int query(int x, int y, int k){
if (k == 1)
return b[x] ^ b[y] ^ a[lca(x, y)];
else{
int nowlca = lca(x, y);
int now = x;
int ans = 0;
while (1){
ans ^= a[now];
if (depth[now] - k < depth[nowlca])
break;
now = find(now, k);
}
int ed = depth[nowlca] + k - depth[now] + depth[nowlca];
if (ed <= depth[y]){
int tmp = depth[y] - ed;
now = find(y, tmp%k);
while (1){
ans ^= a[now];
if (depth[now] - k < ed)
break;
now = find(now, k);
}
}
return ans;
}
}
int main(){
int q;
while (~scanf("%d%d", &n, &q)){
for (int i = 1; i <= n; i++)
head[i] = -1;
for (int i = 1; i < n; i++){
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
presolve();
while (q--){
int u, v, k;
scanf("%d%d%d", &u, &v, &k);
printf("%d\n", query(u, v, k));
}
}
}