POJ 3764 The xor-longest Path 解题报告 字典树

巧了我就是萌 提交于 2020-03-10 00:07:30

POJ 3764 The xor-longest Path

解题思路:dfs算出根到每个节点的异或和,再将每个异或和转换为二进制插入到字典树中(从大到小插,因为高位的异或和更大),然后对于每一个询问,尽量选取一条二进制不同的路线就行。参考了别人的代码,注释我加在代码里了,请看。
在这里插入图片描述

#include<iostream>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<iostream>
#include<math.h>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<cstring>
#include<string>
#include<map>
#include<stack>
#include<stdio.h>
#include<cstdio>
#include<stdlib.h>
#include<fstream>
#include<iomanip>
#pragma warning(disable:4996)
#define INF 0x3f3f3f3f
#define ll long long
#define PI acos(-1.0)
const int N = 1000010;
const int maxn = 1e9;
using namespace std;
int n,num,ans;
int dis[200005], trie[3500005][2];
struct edge {
	int first,next, to, quan;
}a[200005];
void Add(int from, int to, int quan)
{
	num++;//num给边标号
	a[num].to = to;
	a[num].quan = quan;
	a[num].next = a[from].first;//类似链表的方法来记录路径,插入到根和根的next中间,新插入的成为根的next
	a[from].first = num;//由于有first和next,所以节点序号和边标号不会冲突
	//操作节点标号只用first,操作边标号用next,to,quan,所以不会冲突,这样少开一个数组(好像差别不大
}
void dfs(int now, int f)
{
	for (int i = a[now].first; i; i = a[i].next)//每个next存着一个to和一个quan,起点都是now
	{
		int to = a[i].to;
		int quan = a[i].quan;
		if (to == f)
		{
			continue;
		}
		dis[to] = dis[now] ^ quan;//now是节点序号,不是边标号!!
		dfs(to, now);
	}
}
void insert(int h)
{
	int now = 0;
	for (int i = 30; i >= 0; i--)
	{
		int x = h & (1 << i);
		if (x)
			x = 1;
		else
			x = 0;
		if (!trie[now][x])
			trie[now][x] = ++num;//后面find中要用到链表的结构,只能这么赋值
		now = trie[now][x];//关键是序号要+1
	}
}
void find(int h)
{
	int now = 0, tot = 0;
	for (int i = 30; i >= 0; i--)
	{
		int x = (1 << i) & h;
		if (x)
			x =0;
		else
			x =1;
		if (trie[now][x])
			now = trie[now][x], tot += 1 << i;
		else
			now = trie[now][x ^ 1];
	}
	ans = max(ans, tot);
}
int main()
{
	while (scanf("%d", &n) != EOF)
	{
		num = 0, ans = 0;
		memset(a, 0, sizeof(a));
		memset(trie, 0, sizeof(trie));
		memset(dis, 0, sizeof(dis));
		for (int i = 1; i < n; i++)
		{
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			x++, y++;
			Add(x, y, z);
			Add(y, x, z);//边可以反向走,只要不重复经过节点
		}
		dfs(1, 0);
		num = 0;
		for (int i = 1; i <= n; i++)
		{
			insert(dis[i]);
			find(dis[i]);
		}
		printf("%d\n", ans);
	}
}



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!