XOR最小全域木(Codefrces888G + 2020Niukeマルチスクールトレーニング5B質問グラフ)-分割統治+貪欲+01辞書ツリー

私は研究室でこのアルゴリズムを理解する最後の人かもしれません。
ここに画像の説明を挿入
私が理解していない理由は、分割統治がエッジを接続するプロセスである方法を理解したことがないためです。次に、私の記事の出発点はこれを中心に拡張することです。ポイント。他に何もわからない場合は、
RJS
ZiguangJJLに
アクセスしてください。

家に近い

前提知識:01辞書ツリー

ご存知のとおり、nポイントのツリーはn-1個のエッジを接続する必要があります。重みval [i]のポイントが4つあると仮定して、
ここに画像の説明を挿入
最初にツリーを生成させます(最小のXOR値なし)。

1.最初にval [1]とval [2]を接続し、次に2をルートノードとする2つのサブツリーを
接続します。2。val[3]とval [4]を接続して、ルートノードが3になるようにします。サブツリーが接続されています。3。
この時点では、グラフに1つのエッジ
がありません。つまり、ルートノードが1の2つのサブツリーは接続されいません。4。ルートノードが1の2つのサブツリー接続されています。

ここでは、ルートノードとして1を使用して2つのサブツリーを接続する方法が、最小のツリーを生成するための鍵となります。

Val [1]はval [3]
に接続できますval [1 ]はval [4]
に接続できますval [2]はval [3]
に接続できますval [2]はval [4]に接続できます

n-1個のエッジを接続するプロセスを分割統治のアイデアに置き換えることができることがわかります

ルートノードに左と右のサブツリーがある場合は、左と右のサブツリー
を接続するための最小コストを見つける必要があります。
最小コストを見つけるプロセスは、ツリー上で再帰的なプロセスです。

最小XOR値を見つける方法について話すだけです。
配列l [x]、r [x]を使用して、ルートノードの下に含まれる点の重みの数をxで記録します。次に、左右のサブツリーを接続するときに、左側のすべてのサブツリーをトラバースできます右側のサブツリーのツリーは、最小XOR値を最小値に一致させます。

888Gコード

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int maxn = 1e7+ 7;
const ll mod = 1000000007;

#define mst(x, a) memset( x,a,sizeof(x) )
#define rep(i, a, b) for(int i=(a);i<=(b);++i)
#define dep(i, a, b) for(int i=(a);i>=(b);--i)

inline ll read() {
    
    
    ll x = 0;
    bool f = 0;
    char ch = getchar();
    while (ch < '0' || '9' < ch) f |= ch == '-', ch = getchar();
    while ('0' <= ch && ch <= '9')
        x = x * 10 + ch - '0', ch = getchar();
    return f ? -x : x;
}

void out(ll x) {
    
    
    int stackk[20];
    if (x < 0) {
    
    
        putchar('-');
        x = -x;
    }
    if (!x) {
    
    
        putchar('0');
        return;
    }
    int top = 0;
    while (x) stackk[++top] = x % 10, x /= 10;
    while (top) putchar(stackk[top--] + '0');
}

int  n, l[maxn], r[maxn], t[maxn ][2], tot ;
ll a[maxn];
void insert(ll x, ll id) {
    
    
    int p = 0;
    for (int i = 32; i >= 0; i--) {
    
    
        int op = (x >> i) & 1;
        if (!t[p][op]) t[p][op] = ++tot;
        p = t[p][op];
        if (!l[p]) l[p] = id;
        r[p] = id;
    }
}

ll q(ll pp, ll x, ll pos) {
    
    
    ll res = 0, p = pp;
    for (int i = pos; i >= 0; i--) {
    
    
        int op = (x >> i) & 1;
        if (t[p][op]) p = t[p][op];
        else {
    
    
            res += (1 << i);
            p = t[p][op ^ 1];
        }
    }
    return res;
}

ll dfs(ll pp, ll pos) {
    
    
    ll p = pp;
    if (t[p][0] && t[p][1]) {
    
    
        ll x=t[p][0];
        ll y=t[p][1],minn=inf;
        for(int i=l[x];i<=r[x];i++)
        minn=min(minn,q(y,a[i],pos-1)+(1<<pos));
        return minn+dfs(t[p][1], pos - 1)+dfs(t[p][0], pos - 1);
    } else if (t[p][1]) return  dfs(t[p][1], pos - 1);
    else if (t[p][0])  return dfs(t[p][0], pos - 1);
    return 0;
}

int main() {
    
    
    n = read();
    rep(i, 1, n) a[i] = read();
    sort(a + 1, a + 1 + n);
    for (int i = 1; i <= n; i++)  insert(a[i], i);
    out(dfs(0, 32));
    return 0;
}

Bコード

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef unsigned long long ull;
const int inf = 0x3f3f3f3f;
const int maxn = 3e6 + 7;
const ll mod = 1000000007;

#define mst(x, a) memset( x,a,sizeof(x) )
#define rep(i, a, b) for(int i=(a);i<=(b);++i)
#define dep(i, a, b) for(int i=(a);i>=(b);--i)

inline ll read() {
	ll x = 0;
	bool f = 0;
	char ch = getchar();
	while (ch < '0' || '9' < ch) f |= ch == '-', ch = getchar();
	while ('0' <= ch && ch <= '9')
		x = x * 10 + ch - '0', ch = getchar();
	return f ? -x : x;
}

void out(ll x) {
	int stackk[20];
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	if (!x) {
		putchar('0');
		return;
	}
	int top = 0;
	while (x) stackk[++top] = x % 10, x /= 10;
	while (top) putchar(stackk[top--] + '0');
}

int n, l[maxn], r[maxn], t[maxn][2], tot, head[maxn], cnt;
ll a[maxn];
struct node {
	ll u, v, w, next;
} e[maxn];

void add(int u, int v, int w) {
	e[cnt].v = v;
	e[cnt].u = u;
	e[cnt].w = w;
	e[cnt].next = head[u];
	head[u] = cnt++;
}

void insert(ll x, ll id) {
	int p = 0;
	for (int i = 32; i >= 0; i--) {
    
    
		int op = (x >> i) & 1;
		if (!t[p][op]) t[p][op] = ++tot;
		p = t[p][op];
		if (!l[p]) l[p] = id;
		r[p] = id;
	}
}

ll q(ll pp, ll x, ll pos) {
	ll res = 0, p = pp;
	for (int i = pos; i >= 0; i--) {
    
    
		int op = (x >> i) & 1;
		if (t[p][op]) p = t[p][op];
		else {
			res += (1 << i);
			p = t[p][op ^ 1];
		}
	}
	return res;
}

ll dfs(ll pp, ll pos) {
	ll p = pp;
	if (t[p][0] && t[p][1]) {
		ll x = t[p][0];
		ll y = t[p][1], minn = inf;
		for (int i = l[x]; i <= r[x]; i++)
			minn = min(minn, q(y, a[i], pos - 1) + (1 << pos));
		return minn + dfs(t[p][1], pos - 1) + dfs(t[p][0], pos - 1);
	} else if (t[p][1]) return dfs(t[p][1], pos - 1);
	else if (t[p][0]) return dfs(t[p][0], pos - 1);
	return 0;
}
void bfs(int u,int p,ll w) {
	a[u]=w;
	for(int i=head[u]; ~i; i=e[i].next) {
		int v=e[i].v;
		if(v==p) continue;
		bfs(v,u,e[i].w^w);
	}
}
int main() {
	n = read();
	mst(head, -1);
	rep(i, 1, n - 1) {
		int u = read();
		int v = read();
		ll w = read();
		u++,v++;
		add(u, v, w);
		add(v, u, w);
	}
	bfs(1,1,0);
	sort(a + 1, a + 1 + n);
	for (int i = 1; i <= n; i++) insert(a[i], i);
	out(dfs(0, 32));
	return 0;
}

おすすめ

転載: blog.csdn.net/wmy0536/article/details/107714941