ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【Coel.学习笔记】【一个阶段的结束】01-Trie树(01字典树)求异或路径

2022-03-31 20:35:18  阅读:147  来源: 互联网

标签:cnt ch 求异 int Coel edge 异或 01 maxn


题前闲语

是的,变成闲语了(别问我为什么要改)
今天考完了月考,虽然发挥得不是很好但终归是结束了,休息一下~
刚好深进也到货了,开始新一轮学习吧!

题目简介

题目描述

给定一棵 \(n\) 个点的带权树,结点下标从 \(1\) 开始到 \(n\)。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。

输入输出格式

输入格式

第一行一个整数 \(n\),表示点数。
接下来 \(n-1\) 行,给出 \(u,v,w\) ,分别表示树上的 \(u\) 点和 \(v\) 点有连边,边的权值是 \(w\)。

输出格式

一行,一个整数表示答案。

解题思路

考虑用链式前向星存图,求出每个节点到根节点(自行定义根节点为\(1\))的异或路径,那么两个节点的异或路径就是它们与根节点路径的异或值
先用\(dfs\)初始化每个节点的异或值:

struct edge {
    int next, to, w;
} edge[maxn];

int p[maxn], cnt;

void add_edge(int u, int v, int w) {
    edge[++cnt].next = p[u];
    edge[cnt].to = v;
    edge[cnt].w = w;
    p[u] = cnt;
}

void init(int x, int f) {//dfs
    for (int i = p[x]; i != 0; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if (v != f) {
            s[v] = s[x] ^ w;
            init(v, x);
        }
    }
}

然后暴力枚举。当然直接暴力枚举的话复杂度是\(O(n^2)\),没法通过\(n=10^5\),所以需要用\(01-Trie\)优化。
(此处待补充)
代码如下:

#include <cctype>
#include <cstdio>
#include <iostream>
#include <vector>

namespace FastIO {
inline int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    static int buf[35];
    int top = 0;
    do {
        buf[top++] = x % 10;
        x /= 10;
    } while (x);
    while (top)
        putchar(buf[--top] + '0');
    puts("");
}
}  // namespace FastIO

using namespace std;
using namespace FastIO;

const int maxn = 1e5 + 10;

struct edge {
    int next, to, w;
} edge[maxn];

int p[maxn];
int n, cnt, tot, ans;
int s[maxn], ch[maxn * 32][2];

void add_edge(int u, int v, int w) {
    edge[++cnt].next = p[u];
    edge[cnt].to = v;
    edge[cnt].w = w;
    p[u] = cnt;
}

void init(int x, int f) {
    for (int i = p[x]; i != 0; i = edge[i].next) {
        int v = edge[i].to, w = edge[i].w;
        if (v != f) {
            s[v] = s[x] ^ w;
            init(v, x);
        }
    }
}

void insert(int v) {
    int u = 0;
    for (int i = (1 << 30); i; i >>= 1) {
        bool c = v & i;
        if (!ch[u][c])
            ch[u][c] = ++tot;
        u = ch[u][c];
    }
}

int find(int v) {
    int ans = 0, u = 0;
    for (int i = (1 << 30); i; i >>= 1) {
        bool c = v & i;
        if (ch[u][!c]) {
            ans += i;
            u = ch[u][!c];
        } else
            u = ch[u][c];
    }
    return ans;
}

int main() {
    n = read();
    for (int i = 1; i <= n - 1; i++) {
        int u = read(), v = read(), w = read();
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
    init(1, -1);
    for (int i = 1; i <= n; i++)
        insert(s[i]);
    for (int i = 1; i <= n; i++)
        ans = max(ans, find(s[i]));
    write(ans);
    return 0;
}

标签:cnt,ch,求异,int,Coel,edge,异或,01,maxn
来源: https://www.cnblogs.com/Coel-Flannette/p/16083857.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有