一个处理字符串查找 和xort问题的常用工具
1>最长异或路径
给定一棵n个点的带权树,结点下标从1开始到N。寻找树中找两个结点,求最长的异或路径。
异或路径指的是指两个结点之间唯一路径上的所有边权的异或。
1≤n≤100000
0≤w<2^31
题意:
一颗最小生成树,带边权
求 所有路径中,边权异或后得到的值,最大是多少
1)最小生成树,那就先拎出来一个顶点
2)从顶点,分出一条条独立的路径
3)这些路径的起点都是rt,所以每条路径的异或结果都容易记录,记为xo[i](rt->i)
4)尝试将以rt为起点的路径,与其他路径的异或结果建立关系,发现xo(i->j)=xo(rt->i)^xo(rt->j) (rt,i,j的关系任意)
5)肯定不会去枚举,那么我们把xo(rt->i)的值,按照高位到低位的顺序,放在字母树上
6)然后用xo(rt->i)去找,每次找最大值
7)一个ans记录每次的最大值,中的最大值
8)输出ans
#include<cstdio> #include<cstdlib> #include<vector> using namespace std; int n; const int N=100003; struct node { int v,w; node(int vv,int ww) { v=vv,w=ww; } node(){} }; vector <node > g[N]; int xo[N]; void dfs(int nw,int pre) { int sz=g[nw].size() ; for(int i=0;i<sz;i++) { node t=g[nw][i]; if(t.v ==pre) continue; xo[t.v ]=xo[nw]^t.w ; dfs(t.v ,nw ); } } int rt; int trie[N*31][2],cnt; void build(int x) { int pos=rt; for(int i=1<<30;i;i>>=1) { bool tt=i&x; if(!trie[pos][tt]) trie[pos][tt]=++cnt; pos=trie[pos][tt]; } } int ans; int query(int x) { int pos=rt,as=0; for(int i=1<<30;i;i>>=1) { bool tt=x&i; if(trie[pos][tt^1]) pos=trie[pos][tt^1],as+=i; else pos=trie[pos][tt]; } return as; } int main() { scanf("%d",&n); for(int i=1,u,v,w;i<n;i++) scanf("%d%d%d",&u,&v,&w), g[u].push_back(node(v,w)),g[v].push_back(node(u,w)); dfs(1,0); for(int i=1;i<=n;i++) build(xo[i]); for(int i=1;i<=n;i++) ans=max(ans,query(xo[i])); printf("%d ",ans); return 0; }