poj 3764

这题还是比较厉害的。题目

首先这是一颗无根树,不会处理,看了书才知道,我们可以转化为有根树,然后根据树的特性和前缀和的性质,可以得到d[x]=d[fa] xor weight(x,d[fa])。由此我们可以dfs出所有点的d,对于任意两点的路径异或,就是d[x] xor d[y],这个是因为异或的性质得到的,用手画两条路径就明白了,就可以转化为序列中任意两个数异或最大值了。(树转序列好像也是一个方向)

当然这题有点卡空间,当list空间过不去,可以用链式前向星,我觉得trie的题都比较耗空间,要建树和图都用前向星吧。

#include<cstdio>
#include<algorithm>
#include<list>
#include<cstring>
#include<iostream>
#include<bitset>
#define int long long
using namespace std;
int trie[100002*33][2],n,u,v,d[100002],ans,k,head[100002],e[100002*2],len[100002*2],nxt[100002*2],num;
bool vis[100002];
void add(int uu,int vv,int ww)
{
	e[++num]=vv;
    len[num]=ww;
    nxt[num]=head[uu];
    head[uu]=num;
}
void dfs(int rt)
{
	vis[rt]=true;
	for(int i=head[rt];i;i=nxt[i])
	{
		int to=e[i],wei=len[i];
		if(!vis[to])
		{
			d[to]=d[rt]^wei;
			dfs(to);
		}
	}
}
void inse(int x)
{
	int p=0;
	for(int i=31;i>=0;i--)
	{
		int c=(x>>i)&1;
		if(!trie[p][c])
		{
			trie[p][c]=k++;
		}
		p=trie[p][c];
	}
}
int fin(int x)
{
	int p=0,anss=0;
	for(int i=31;i>=0;i--)
	{
		int c=(x>>i)&1;
		int o=c^1;
		if(trie[p][o])
		{
			p=trie[p][o];
			anss=anss<<1|1;
		}
		else
		{
			p=trie[p][c];
			anss=anss<<1;
		}
	}
	return anss;
}
signed main()
{
	while(scanf("%lld",&n)!=EOF)
	{
		num=0;
		k=1;
		ans=0;
		memset(trie,0,sizeof(trie));
		memset(vis,false,sizeof(vis));
		memset(d,0,sizeof(d));
		memset(head,0,sizeof(head));
    	memset(nxt,0,sizeof(nxt));
    	//memset(v,0,sizeof(v));
		for(int i=1;i<=n-1;i++)
		{
			int u,v,w;
			scanf("%lld %lld %lld",&u,&v,&w);
			add(u,v,w);
			add(v,u,w);
		}
		dfs(1);
		for(int i=0;i<n;i++)
		{
			ans=max(ans,fin(d[i]));
			inse(d[i]);
		}
		/*for(int i=0;i<n;i++)
        {
        	printf("%d ",d[i]);
		}
		printf("\n");*/
		cout<<ans<<endl;
	}
 } 

猜你喜欢

转载自blog.csdn.net/qq_37073764/article/details/107352055