01Trie树模板 - 亦或最小生成树

01Trie树模板 - 亦或最小生成树

CF888G Xor-MST


题意

  • 给定一个有 n n n个结点的图的点权
  • 连每两个点的边权是两端点点权的亦或值
  • 求该图最小生成树值和

数据范围: 1 ≤ n ≤ 2 × 1 0 5 , a i ≤ 2 30 1\leq n\leq 2\times 10^5 , a_i \leq 2^{30} 1n2×105,ai230


前置技能

  • 01trie树 (没学01trie树来这儿干啥)

Tutorial:

  • 原理

插入查找复杂度: O ( l o g ( v a l ) ) O(log(val)) O(log(val))

总空间复杂度: O ( n × 40 ) O(n\times40) O(n×40)


code~~(板子)~~:


#include 

using namespace std;

#define local
#ifdef local

template<class T>
void _E(T x) { cerr << x; }

void _E(double x) { cerr << fixed << setprecision(6) << x; }

void _E(string s) { cerr << "\"" << s << "\""; }

template<class A, class B>
void _E(pair<A, B> x) {
    cerr << '(';
    _E(x.first);
    cerr << ", ";
    _E(x.second);
    cerr << ")";
}

template<class T>
void _E(vector<T> x) {
    cerr << "[";
    for (auto it = x.begin(); it != x.end(); ++it) {
        if (it != x.begin()) cerr << ", ";
        _E(*it);
    }
    cerr << "]";
}

void ERR() {}

template<class A, class... B>
void ERR(A x, B... y) {
    _E(x);
    cerr << (sizeof...(y) ? ", " : " ");
    ERR(y...);
}

#define debug(x...) do { cerr << "{ "#x" } -> { "; ERR(x); cerr << "}" << endl; } while(false)
#else
#define debug(...) 114514.1919810
#endif
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3f
#define ll long long
#define db long double
#define eps 1e-3
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair
#define pdd pair
#define endl "\n"
#define ls ch[now][0]
#define rs ch[now][1]
const ll mod = 998244353;
const ll maxn = 2e5 + 10;


ll qpow(ll a, ll b) {
    ll ret = 1;
    for (; b; a = a * a % mod, b >>= 1) {
        if (b & 1) {
            ret = ret * a % mod;
        }
    }
    return ret;
}

vector<ll> f(maxn), invf(maxn);

ll inv(ll a) {
    return qpow(a, mod - 2);
}

void prework() {
    f[0] = 1;
    _rep(i, 1, maxn - 1) {
        f[i] = f[i - 1] * i % mod;
    }
    invf[maxn - 1] = qpow(f[maxn - 1], mod - 2);
    for (ll i = maxn - 2; i >= 0; i--) {
        invf[i] = invf[i + 1] * (i + 1) % mod;
    }

}

ll C(ll n, ll m) {
    if (n > m || m < 0)return 0;
    if (n == 0 || m == n) return 1;
    ll res = (f[m] * invf[m - n] % mod * invf[n]) % mod;
    return res;
}

vector<pii > G[maxn];


struct Trie {
    ll son[2][3500005], tot;
    ll u[3500005];//下标关系映射

    void insert(ll a, ll th = 0) {
        ll now = 0, id;
        for (ll i = 30; i >= 0; i--) {
            id = (a >> i) & 1;
            if (!son[id][now])son[id][now] = ++tot;
            now = son[id][now];
        }
        u[now] = th;
    }

    ll ask(ll val, ll cur = 0, ll deep = 30) {
        if (deep < 0)
            return u[cur];
        ll op = (val >> deep) & 1;
        if (son[op ^ 1][cur])
            return ask(val, son[op ^ 1][cur], deep - 1);
        else
            return ask(val, son[op][cur], deep - 1);
    }

    ll find(ll r1, ll r2, ll b) {
        if (b < 0) return 0;
        ll a1 = -1, a2 = -1;
        if (son[0][r1] && son[0][r2]) a1 = find(son[0][r1], son[0][r2], b - 1);
        if (son[1][r1] && son[1][r2]) a2 = find(son[1][r1], son[1][r2], b - 1);
        if (~a1 && ~a2) return min(a1, a2);
        if (~a1) return a1;
        if (~a2) return a2;
        if (son[1][r1] && son[0][r2]) a1 = find(son[1][r1], son[0][r2], b - 1) + (1 << b);
        if (son[0][r1] && son[1][r2]) a2 = find(son[0][r1], son[1][r2], b - 1) + (1 << b);
        if (~a1 && ~a2) return min(a1, a2);
        if (~a1) return a1;
        if (~a2) return a2;
    }

    void clear() {
        met(son, 0);
        met(u, 0);
        tot = 0;
    }
} T;

//long long ans;
//
//void dfs(ll a, ll b) {
//    if (b < 0) return;
//    if (T.son[0][a] && T.son[1][a]) ans += 1ll * T.find(T.son[0][a], T.son[1][a], b - 1) + (1ll << b);
//    if (T.son[0][a]) dfs(T.son[0][a], b - 1);
//    if (T.son[1][a]) dfs(T.son[1][a], b - 1);
//}
vector<ll> a;

void dfs(int cur, int fa) {

    for (auto i:G[cur]) {
        if (i.first == fa) {
            continue;
        }
        a[i.first] = a[cur] ^ i.second;
        dfs(i.first, cur);
    }
}

ll solve(int a, int deep) {
    ll ret = 0;
    if (deep < 0)return 0;
    if (T.son[0][a] && T.son[1][a]) ret += T.find(T.son[0][a], T.son[1][a], deep - 1) + (1ll << deep);
    if(T.son[0][a]) ret += solve(T.son[0][a],deep-1);
    if(T.son[1][a])ret +=solve(T.son[1][a],deep-1);
    return ret;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin >> n;

    _rep(i, 1, n) {
        int x;
        cin >> x;
        T.insert(x);
    }
    cout << solve(0, 30) << endl;
}

牛客多校第五场B-Graph


题意

  • 给定一棵带边权的树
  • 现在你可以任意删边加边, 只要满足
    • 图联通
    • 环的亦或和等于0
  • 求该图最小生成树值和

数据范围: 1 ≤ n ≤ 2 × 1 0 5 , a i ≤ 2 30 1\leq n\leq 2\times 10^5 , a_i \leq 2^{30} 1n2×105,ai230


前置技能

  • 01trie树 (没学01trie树来这儿干啥)

Tutorial:

  • 考虑树上亦或

  • 维护 a i a_i ai 为从根到 i i i节点的亦或和, 发现 a i a_i ai可以的当作上一题点权处理


code~~(板子)~~:

#include 

using namespace std;

#define local
#ifdef local

template<class T>
void _E(T x) { cerr << x; }

void _E(double x) { cerr << fixed << setprecision(6) << x; }

void _E(string s) { cerr << "\"" << s << "\""; }

template<class A, class B>
void _E(pair<A, B> x) {
    cerr << '(';
    _E(x.first);
    cerr << ", ";
    _E(x.second);
    cerr << ")";
}

template<class T>
void _E(vector<T> x) {
    cerr << "[";
    for (auto it = x.begin(); it != x.end(); ++it) {
        if (it != x.begin()) cerr << ", ";
        _E(*it);
    }
    cerr << "]";
}

void ERR() {}

template<class A, class... B>
void ERR(A x, B... y) {
    _E(x);
    cerr << (sizeof...(y) ? ", " : " ");
    ERR(y...);
}

#define debug(x...) do { cerr << "{ "#x" } -> { "; ERR(x); cerr << "}" << endl; } while(false)
#else
#define debug(...) 114514.1919810
#endif
#define _rep(n, a, b) for (ll n = (a); n <= (b); ++n)
#define _rev(n, a, b) for (ll n = (a); n >= (b); --n)
#define _for(n, a, b) for (ll n = (a); n < (b); ++n)
#define _rof(n, a, b) for (ll n = (a); n > (b); --n)
#define oo 0x3f3f3f3f3f3f
#define ll long long
#define db long double
#define eps 1e-3
#define bin(x) cout << bitset<10>(x) << endl;
#define what_is(x) cerr << #x << " is " << x << endl
#define met(a, b) memset(a, b, sizeof(a))
#define all(x) x.begin(), x.end()
#define pii pair
#define pdd pair
#define endl "\n"
#define ls ch[now][0]
#define rs ch[now][1]
const ll mod = 998244353;
const ll maxn = 2e5 + 10;


ll qpow(ll a, ll b) {
    ll ret = 1;
    for (; b; a = a * a % mod, b >>= 1) {
        if (b & 1) {
            ret = ret * a % mod;
        }
    }
    return ret;
}

vector<ll> f(maxn), invf(maxn);

ll inv(ll a) {
    return qpow(a, mod - 2);
}

void prework() {
    f[0] = 1;
    _rep(i, 1, maxn - 1) {
        f[i] = f[i - 1] * i % mod;
    }
    invf[maxn - 1] = qpow(f[maxn - 1], mod - 2);
    for (ll i = maxn - 2; i >= 0; i--) {
        invf[i] = invf[i + 1] * (i + 1) % mod;
    }

}

ll C(ll n, ll m) {
    if (n > m || m < 0)return 0;
    if (n == 0 || m == n) return 1;
    ll res = (f[m] * invf[m - n] % mod * invf[n]) % mod;
    return res;
}

vector<pii > G[maxn];


struct Trie {
    ll son[2][3500005], tot;
    ll u[3500005];//下标关系映射

    void insert(ll a, ll th = 0) {
        ll now = 0, id;
        for (ll i = 30; i >= 0; i--) {
            id = (a >> i) & 1;
            if (!son[id][now])son[id][now] = ++tot;
            now = son[id][now];
        }
        u[now] = th;
    }

    ll ask(ll val, ll cur = 0, ll deep = 30) {
        if (deep < 0)
            return u[cur];
        ll op = (val >> deep) & 1;
        if (son[op ^ 1][cur])
            return ask(val, son[op ^ 1][cur], deep - 1);
        else
            return ask(val, son[op][cur], deep - 1);
    }

    ll find(ll r1, ll r2, ll b) {
        if (b < 0) return 0;
        ll a1 = -1, a2 = -1;
        if (son[0][r1] && son[0][r2]) a1 = find(son[0][r1], son[0][r2], b - 1);
        if (son[1][r1] && son[1][r2]) a2 = find(son[1][r1], son[1][r2], b - 1);
        if (~a1 && ~a2) return min(a1, a2);
        if (~a1) return a1;
        if (~a2) return a2;
        if (son[1][r1] && son[0][r2]) a1 = find(son[1][r1], son[0][r2], b - 1) + (1 << b);
        if (son[0][r1] && son[1][r2]) a2 = find(son[0][r1], son[1][r2], b - 1) + (1 << b);
        if (~a1 && ~a2) return min(a1, a2);
        if (~a1) return a1;
        if (~a2) return a2;
    }

    void clear() {
        met(son, 0);
        met(u, 0);
        tot = 0;
    }
} T;

//long long ans;
//
//void dfs(ll a, ll b) {
//    if (b < 0) return;
//    if (T.son[0][a] && T.son[1][a]) ans += 1ll * T.find(T.son[0][a], T.son[1][a], b - 1) + (1ll << b);
//    if (T.son[0][a]) dfs(T.son[0][a], b - 1);
//    if (T.son[1][a]) dfs(T.son[1][a], b - 1);
//}
vector<ll> a;

void dfs(int cur, int fa) {

    for (auto i:G[cur]) {
        if (i.first == fa) {
            continue;
        }
        a[i.first] = a[cur] ^ i.second;
        dfs(i.first, cur);
    }
}

ll solve(int a, int deep) {
    ll ret = 0;
    if (deep < 0)return 0;
    if (T.son[0][a] && T.son[1][a]) ret += T.find(T.son[0][a], T.son[1][a], deep - 1) + (1ll << deep);
    if(T.son[0][a]) ret += solve(T.son[0][a],deep-1);
    if(T.son[1][a])ret +=solve(T.son[1][a],deep-1);
    return ret;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int n;
    cin >> n;
    _rep(i, 1, n - 1) {
        int u, v, w;
        cin >> u >> v >> w;
        u++, v++;
        G[u].emplace_back(v, w);
        G[v].emplace_back(u, w);
    }
    a.resize(n + 1);
    dfs(1, 0);

    _rep(i, 1, n) {
        T.insert(a[i]);
    }
    cout << solve(0, 30) << endl;
}

你可能感兴趣的:(01trie树真的飘逸,trie树,拦住我的好题)