Namomo Spring Camp 2022 Div1 #451. Dis

451. Dis

题目链接

题意 | 简单

给出 n 个点的一棵树,每个点有各自的点权,m 次询问两个点简单路径所构成点集的异或和。
1 ≤ \leq n , m n,m nm ≤ \leq 2 e 5 2e^5 2e5 , 1 ≤ \leq ai ≤ \leq 1 0 9 10^9 109

思路 | 倍增

已知给出的是一颗树,在树上直接求 l c a lca lca ,把每个点权放进去通过倍增预处理一下,最后注意一下板子的边界就好了
数据量有点大,记得开快读~

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
#include<map>
#include<queue>
#define pi acos(-1)
#define e exp(1)
#define For(i, a, b) for(int (i) = (a); (i) <= (b); (i) ++)
#define Bor(i, a, b) for(int (i) = (b); (i) >= (a); (i) --)
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define eps 1e-7
#define INF 0x3f3f3f3f
#define inf -2100000000
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int maxn = 2e5 + 10;
const double EPS = 1e-10;
const ll mod = 1e9 + 7;
inline int read() {
    int ret = 0, f = 0; char ch = getchar();
    while (ch > '9' || ch < '0') f ^= ch == '-', ch = getchar();
    while (ch <= '9' && ch >= '0') ret = ret * 10 + ch - '0', ch = getchar();
    return f ? -ret : ret;
}

int a[maxn];
vector<int>g[maxn];
int fa[maxn][20];
int xo[maxn][20];  
int n, m;
int depth[maxn];
void dfs(int u, int f,int d) {
    fa[u][0] = f;
    xo[u][0] = a[f];
    depth[u] = d;
    int len = g[u].size();
    for (int i = 0; i < len; i++) {
        int v = g[u][i];
        if (v == f) continue;
        dfs(v, u, d + 1);
    }
}
void init() {
    for (int i = 1; i < 20; i++) {
        for (int j = 1; j <= n; j++) {
            fa[j][i] = fa[fa[j][i - 1]][i - 1];
            xo[j][i] = xo[j][i - 1] ^ xo[fa[j][i - 1]][i - 1];
        }
    }
}
int lca(int x,int y) {
    if (depth[x] < depth[y]) swap(x, y);
    int ans = 0;
    for (int i = log2(depth[x] - depth[y]); i >= 0; i--) {
        if ((1 << i) <= depth[x] - depth[y]) ans ^= xo[x][i] ,x = fa[x][i];
    }
    if (x == y) return ans ^ a[y];
    for (int i = log2(depth[x]); i >= 0; i--) {
        if (fa[x][i] != fa[y][i]) {
            ans ^= xo[x][i];
            ans ^= xo[y][i];
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    ans ^= xo[x][0];
    return ans;
}
void solve() {  
    n = read(); m = read();
    for (int i = 1; i <= n; i++) a[i] = read();
    for (int i = 1; i < n; i++) {
        int u, v; u = read(); v = read();
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 1, 0);
    init();
    while (m--) {
        int u, v;
        u = read(); v = read();
        int ans = lca(u, v) ^ a[u] ^ a[v];
        if (u == v) printf("%d\n", a[u]);
        else printf("%d\n", ans);
    }
}
int main() {
    int t;
    t = 1;
    while (t--) {
        solve();
    }
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值