ACwing 144. 最长异或值路径 字典树

给定一个树,树上的边都具有权值。

树中一条路径的异或长度被定义为路径上所有边的权值的异或和:

formula.png

⊕ 为异或符号。

给定上述的具有n个节点的树,你能找到异或长度最大的路径吗?
输入格式

第一行包含整数n,表示树的节点数目。

接下来n-1行,每行包括三个整数u,v,w,表示节点u和节点v之间有一条边权重为w。
输出格式

输出一个整数,表示异或长度最大的路径的最大异或和。
数据范围

1≤n≤100000
,
0≤u,v<n,
0≤w<231

输入样例:

4
0 1 3
1 2 4
1 3 6

输出样例:

7

样例解释

样例中最长异或值路径应为0->1->2,值为7 (=3 ⊕ 4)

题意: 一棵树,有边权,求任意两点 U , V U,V U,V的路径上的亦或和最大


先推荐Y总的视频题解: https://www.acwing.com/video/81/



首先,假如选定一个根节点(例如0节点),
设根节点大到 U U U节点的异或和为 s u m u sum_u sumu
如下图, 5 5 5 9 9 9的路径异或和应该为 s u m 5 <mtext>   </mtext> x o r <mtext>   </mtext> s u m 9 sum_5~xor~sum_9 sum5 xor sum9
因为 s u m 2 sum_2 sum2会被 x o r xor两次 xor而消掉

dfs求出到每个点的路径异或和 s u m u sum_u sumu后,就变成了:
n n n s u m u sum_u sumu里挑出 A A A B B B,使得 A <mtext>   </mtext> x o r <mtext>   </mtext> B A~xor~B A xor B最大,
也就是AcWing 143. 最大异或对那题的题意

#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif

#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>

#define MAXN ((int)1e5+7)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)

using namespace std;

#define show(x...) \ do { \ cout << "\033[31;1m " << #x << " -> "; \ err(x); \ } while (0)

void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }

namespace FastIO{

	char print_f[105];
	void read() {}
	void print() { putchar('\n'); }

	template <typename T, typename... T2>
		inline void read(T &x, T2 &... oth) {
			x = 0;
			char ch = getchar();
			ll f = 1;
			while (!isdigit(ch)) {
				if (ch == '-') f *= -1; 
				ch = getchar();
			}
			while (isdigit(ch)) {
				x = x * 10 + ch - 48;
				ch = getchar();
			}
			x *= f;
			read(oth...);
		}
	template <typename T, typename... T2>
		inline void print(T x, T2... oth) {
			ll p3=-1;
			if(x<0) putchar('-'), x=-x;
			do{
				print_f[++p3] = x%10 + 48;
			} while(x/=10);
			while(p3>=0) putchar(print_f[p3--]);
			putchar(' ');
			print(oth...);
		}
} // namespace FastIO
using FastIO::print;
using FastIO::read;

int n, m, Q, K;
/** struct Node { Node* next[2]; Node() { memset(next, false, sizeof(next)); } } *root = new Node(); */
#define ch ( x >> i & 1 )
#define N 31
#if 0
void insert(int x) {
	Node* now = root;
	for(int i=N; i>=0; i--) {
		if(!now->next[ch]) now->next[ch] = new Node();
		now = now->next[ch];
	}
}

int search(int x) {
	Node* now = root;
	int ans = 0;
	for(int i=N; i>=0; i--) {
		if(now->next[!ch]) {
			ans += 1 << i;
			now = now->next[!ch];
		} else {
			now = now->next[ch];
		}
	}
	return ans;
}
#endif

struct Node {
	int v, w;
} ;

vector<Node> G[MAXN];

int a[MAXN], tot;
int tree[MAXN*32][2];
void insert(int x) {
	int now = 0;
	for(int i=N; i>=0; i--) {
		if(!tree[now][ch]) tree[now][ch] = ++tot;
		now = tree[now][ch];
	}
}

int search(int x) { //找打一个数,尽量使得二进制位前面的1最多
	int now = 0, ans = 0;
	for(int i=N; i>=0; i--) {
		if(tree[now][!ch]) { //因为不同才为1,所以每一步尽量走相反的位
			ans += 1 << i;
			now = tree[now][!ch];
		} else {
			now = tree[now][ch];
		}
	}
	return ans;
}

bool vis[MAXN];
void dfs(int u, int sum) {
	vis[u] = true;
	a[u] = sum;
	for(auto ed : G[u]) {
		int v = ed.v;
		if(vis[v]) continue ;
		dfs(v, sum^ed.w);
	}
}

int main() {
#ifdef debug
	freopen("test", "r", stdin);
	clock_t stime = clock();
#endif
	read(n);
	int u, v, w;
	for(int i=1; i<n; i++) {
		read(u, v, w);
		G[u].push_back({v, w}), G[v].push_back({u, w});
	}
	dfs(0, 0);
	for(int i=0; i<n; i++)
		insert(a[i]);
	int ans = 0;
	for(int i=0; i<n; i++)
		ans = max(ans, search(a[i]));
	printf("%d\n", ans);


#ifdef debug
	clock_t etime = clock();
	printf("rum time: %lf 秒\n",(double) (etime-stime)/CLOCKS_PER_SEC);
#endif 
	return 0;
}




全部评论

相关推荐

Java抽象带篮子:难蚌,点进图片上面就是我的大头😆
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务