首页 > 其他 > 详细

不正常国家

时间:2021-04-10 16:17:01      阅读:9      评论:0      收藏:0      [点我收藏+]

一棵树,两点间的路径长度定义为经过点权值的异或和。对于每个点 \(i\), 求:

\[\max_{lca(u,v)=i} dis(u,v) \]

先求根缀异或和 \(a\),这样 \(dis(u,v)=a[u]\text{^} a[v] \text{^} a[lca(u,v)]\)

看到异或容易想到01trie合并,和线段树合并方法一样,每个点 \(i\) 开个01trie往上合并,同时在两棵01trie中查异或起来异或 \(a[i]\) 最大的数(详见代码)。

直接交上去T掉,用启发式合并,先处理重儿子,再处理轻儿子就行了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 100005;

struct node {
	node *ch[2];
	inline node () {
		ch[0] = ch[1] = NULL;
	}
} poor[N * 64];

node *root[N];

int en = 0, top = 0;

struct edge {
	int head, to, nxt;
} ed[N << 1];

inline void addedge(int from, int to) {
	ed[++en].to = to; ed[en].nxt = ed[from].head; ed[from].head = en;
}

int a[N], ans[N];

inline void insert(node *rt, int p) {
	node *cur = rt;
	if (cur == NULL) cur = &poor[top++];
	for (register int i = 31; ~i; --i) {
		int t = (p >> i) & 1;
		if (cur -> ch[t] == NULL) (cur -> ch[t]) = &poor[top++];
		cur = cur -> ch[t];
	}
}

inline int max_(int a, int b) {
	return a > b ? a : b;
}

inline int get(node *rta, node *rtb, int dep, int p) {
	if (rta == NULL || rtb == NULL) return 0;
	if (dep < 0) return 0;
	int ans = 0, flag = 0, t = (p >> dep) & 1;
	if (rta -> ch[0] != NULL) {
		if (rtb -> ch[1 ^ t] != NULL) ans = get(rta -> ch[0], rtb -> ch[1 ^ t], dep - 1, p) + (1 << dep), flag = 1;
		else ans = get(rta -> ch[0], rtb -> ch[0 ^ t], dep - 1, p);
	}
	if (rta -> ch[1] != NULL) {
		if (rtb -> ch[0 ^ t] != NULL) ans = max_(ans, get(rta -> ch[1], rtb -> ch[0 ^ t], dep - 1, p) + (1 << dep));
		else if (!flag) ans = max_(ans, get(rta -> ch[1], rtb -> ch[1 ^ t], dep - 1, p));
	} return ans;
}

inline node* merge(node *rta, node *rtb) {
	if (rta == NULL) return rtb;
	if (rtb == NULL) return rta;
	node *ret = &poor[top++];
	ret -> ch[0] = merge(rta -> ch[0], rtb -> ch[0]);
	ret -> ch[1] = merge(rta -> ch[1], rtb -> ch[1]);
	return ret;
}

int siz[N];

inline void dfs(int now, int fa) {
	root[now] = &poor[top++]; siz[now] = 1; int zson = 0;
	int t = ans[now] = a[now]; a[now] ^= a[fa]; insert(root[now], a[now]);
	for (register int i = ed[now].head; i; i = ed[i].nxt) {
		int v = ed[i].to; if (v == fa) continue; 
		dfs(v, now); siz[now] += siz[v];
		if (siz[v] > siz[zson]) zson = v;
//		root[now] = merge(root[now], root[v]);
//		ans[now] = max_(ans[now], get(root[v], root[now], 31, t));
	}if (zson) {
		ans[now] = max_(ans[now], get(root[now], root[zson], 31, t));
		root[now] = merge(root[now], root[zson]);
	}
	for (register int i = ed[now].head; i; i = ed[i].nxt) {
		int v = ed[i].to; if (v == fa) continue; 
		if (v != zson) {
			ans[now] = max_(ans[now], get(root[v], root[now], 31, t));
			root[now] = merge(root[now], root[v]);
		}
	} 
}

int n, u, v;

inline int read() {
	register int s = 0;
	register char ch = getchar();
	while (!isdigit(ch)) ch = getchar();
	while (isdigit(ch)) s = (s << 1) + (s << 3) + (ch & 15), ch = getchar();
	return s;
}

inline void otp(int a) {
	a >= 10 ?  otp(a / 10), putchar((a % 10) ^ 48) : putchar(a ^ 48);
}

int main() {
	freopen("irregular.in", "r", stdin);freopen("irregular.out", "w", stdout);
	n = read();
	for (register int i = 1; i <= n; ++i) a[i] = read();
	for (register int i = 1; i < n; ++i) {
		u = read(); v = read();
		addedge(u, v); addedge(v, u);
	} a[0] = 0; dfs(1, 0);
	for (register int i = 1; i <= n; ++i) otp(ans[i]), putchar(‘ ‘);
	fclose(stdin); fclose(stdout); return 0;
}

不正常国家

原文:https://www.cnblogs.com/wwlwakioi/p/14640423.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!