【Coel.學習筆記】【一個階段的結束】01-Trie樹(01字典樹)求異或路徑
阿新 • • 發佈:2022-03-31
題前閒語
是的,變成閒語了(別問我為什麼要改)
今天考完了月考,雖然發揮得不是很好但終歸是結束了,休息一下~
剛好深進也到貨了,開始新一輪學習吧!
題目簡介
題目描述
給定一棵 \(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; }