【P4551 最長異或路徑】題解
阿新 • • 發佈:2022-01-12
題目連結
題目
給定一棵 \(n\) 個點的帶權樹,結點下標從 \(1\) 開始到 \(n\)。尋找樹中找兩個結點,求最長的異或路徑。
異或路徑指的是指兩個結點之間唯一路徑上的所有邊權的異或
思路
預處理每個點到根節點路勁的異或和,建一棵01trie樹。
對於每個節點,在trie樹上找離它最遠的節點,最後取個 \(\max\) 值即可。
總結
這道題應該也算兩個經典問題的集合吧?
首先求樹上兩個節點之間路徑的異或和,這是一個非常經典的問題,由於重複異或沒影響,所以可以用樹形dp預處理。
這道題巧妙就巧妙在他運用了Trie樹,出現異或,還要求最大,trie樹是一種非常常用的方法,遇到這種情況可以往Trie樹的方面來想。
Code
作者: zhangtingxi 轉載請註明出處: https://www.cnblogs.com/zhangtingxi/p/15792154.html// Problem: P4551 最長異或路徑 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P4551 // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include<bits/stdc++.h> using namespace std; //#define int long long inline int read(){int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+ (x<<3)+(ch^48);ch=getchar();}return x*f;} //#define M //#define mo #define N 100010 struct node { int x, y, z, n; }dx[N*2]; struct Node { int s[2]; }d[N*30]; int n, m, i, j, k; int dp[N], u, v, w, h[N]; int ans, cnt; void cun(int x, int y, int z) { dx[++k].x=x; dx[k].y=y; dx[k].z=z; dx[k].n=h[x]; h[x]=k; } void dfs(int x, int fa) { for(int g=h[x]; g; g=dx[g].n) { int y=dx[g].y; if(y==fa) continue; dp[y]=dp[x]^dx[g].z; dfs(y, x); } } void trie(int x) { int i, j, p=1; for(i=30; i>=0; --i) { j=(x&(1<<i))>0; if(!d[p].s[j]) d[p].s[j]=++cnt; p=d[p].s[j]; } } int find(int dep, int x, int p) { if(dep<0) return 0; int i=(x&(1<<dep))>0; return find(dep-1, x, (d[p].s[i^1] ? d[p].s[i^1] : d[p].s[i]) )+(d[p].s[i^1] ? (1<<dep) : 0); } signed main() { // freopen("tiaoshi.in", "r", stdin); // freopen("tiaoshi.out", "w", stdout); n=read(); for(i=1; i<n; ++i) { u=read(); v=read(); w=read(); cun(u, v, w); cun(v, u, w); } dfs(1, 0); for(cnt=i=1; i<=n; ++i) trie(dp[i]); for(i=1; i<=n; ++i) ans=max(ans, find(30, dp[i], 1)); printf("%d", ans); return 0; }