Luogu P4551 最長異或路徑

題目鏈接:傳送門
在樹中找兩個節點使他們的異或路徑最大

01trie是個好東西
比如今年十二省聯考的day1 t1,加個可持久化而已
跟普通trie相比就是每個節點存的是二進制0或1
從根到一個節點的二進制連起來存的就是一個數字
這樣可以讓你在樹上貪心
因爲深度越大的節點若爲1則這個值一定更大
比如8(1000)> 7(111)
對於這個題
處理出根節點到每個節點的異或
挨個插入到01trie中
遍歷每個節點求最大值
看代碼還是很好理解的

/**
 * @Date:   2019-04-11T19:24:10+08:00
 * @Last modified time: 2019-04-13T10:33:57+08:00
 */
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <complex>
#include <algorithm>
#include <climits>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define A 2000010
#define B 2010

using namespace std;
typedef long long ll;
struct node {
    int next, to, w;
}e[A];
int head[A], num;
void add(int fr, int to, int w) {
    e[++num].next = head[fr];
    e[num].to = to;
    e[num].w = w;
    head[fr] = num;
}
int ch[A][2], n, a, b, c, cnt = 1;
ll s[A];
void dfs(int fr, int faa) {
    for (int i = head[fr]; i; i = e[i].next) {
        int ca = e[i].to;
        if (ca == faa) continue;
        s[ca] = s[fr] ^ e[i].w;
        dfs(ca, fr);
    }
}
void insert(ll x, int fr = 1) {
    for (int i = 32; i >= 0; i--) {
        int pos = (x >> i) & 1; //x的從右數第i位是0還是1
        if (!ch[fr][pos]) ch[fr][pos] = ++cnt;
        fr = ch[fr][pos];
    }
}
ll ask(ll x, int fr = 1, ll ans = 0) {
    for (int i = 32; i >= 0; i--) {
        int pos = (x >> i) & 1; //選擇對應位不同的繼續走
        if (ch[fr][pos ^ 1]) ans += 1LL << i, fr = ch[fr][pos ^ 1];
        else fr = ch[fr][pos];
    }
    return ans;
}

int main(int argc, char const *argv[]) {
	cin >> n;
    for (int i = 1; i < n; i++) cin >> a >> b >> c, add(a, b, c), add(b, a, c);
    dfs(1, 0); ll ans = 0;
    for (int i = 1; i <= n; i++) insert(s[i]);
    for (int i = 1; i <= n; i++) ans = max(ans, ask(s[i]));
    cout << ans << endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章