异或最小生成树 (Codefrces888G +2020牛客多校训练5 B题 Graph)--分治+贪心+01字典树

我可能是实验室最后一个弄明白这个算法的
在这里插入图片描述
我之所以一直没懂就是一直不理解分治是如何替代的 连边的这个过程,那我这篇文章的出发点就是围绕这个点展开的,如果还有别的地方不懂的话可以访问
RJS
紫光
JJL

言归正传

前置知识: 01字典树

众所周知, n个点的树 需要连接n-1条边,假设我们有四个点 的权值 val[i]
在这里插入图片描述
我们先让他生成一个树(不用异或值最小)

1.我们先联通 val【1】和val【2】 那么这样以2为根节点的两颗子树就联通了,
2 .联通 val【3】和val【4】 那么这样以3为根节点的两颗子树就联通了,
3. 此时,图中还缺一条边,也就是以1 为根节点的两颗子树没有联通
4. 联通 以 1 为根节点的两颗子树

这里如何联通以1 为根节点的两颗子树就是生成最小树的关键

可以val[1]连接val[3]
可以val[1]连接val[4]
可以val[2]连接val[3]
可以val[2]连接val[4]

由此可见,我们可以用分治的思想来代替这连接n-1条边的这个过程

如果一个根节点存在左右子树
那么你需要寻找联通左右子树的最小代价
寻找最小代价的过程就是在树上递归的过程

简单说一下如何求最小异或值
用一个数组 l[x],r[x]来记录以 x为根节点下的包含的点权的编号 然后 连接左右子树的时候可以遍历左子树中所有的树在右子树匹配一个最小异或值 去最小值即可

888G code

#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 code

#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