题意:
给出一棵树,求树中最长的xor路径。(n<=100000)
输入 点的数量n,之后n-1行代表x点到y点间有一条权值为z的边;
输出 最优解;
这道题与一般的最长路径不相同,因为考虑到了一个陌生的操作——异或;
异或这种东西和加减乘除还是有区别的,但是还是有一些性质让我们在计算时有据可查;以下是异或运算的性质;
1、交换律
2、结合律(即(a^b)^c == a^(b^c))
3、对于任何数x,都有x^x=0,x^0=x
4、自反性 A XOR B XOR B = A xor 0 = A
好,我们现在可以来看这道题相关的内容;因为题中是一棵树,我们可以像单源最短路那样求出某一个点到所有点的XOR路径;
但是为什么要这样求呢?
我们看图:
比如我现在已经求出了点1到每一个点的异或路径表示为w[2~5].但我现在要枚举到点4到点5之间的XOR路径,怎么办?
其实我直接w[4]^w[5]即可,为什么。其实这里面1和3的路径异或了两次,由于自反性,和没异或是一样的!
所以这个问题就解决了,但是还有一个问题就是:我怎么找最大路径,难道真的要一个一个枚举么?那TLE稳稳地啊;
怎么办,可以把int类型所对应的三十来位01串扔到字典树里;
扔到字典树里有什么用呢?我就可以方便地找出那个最大的啊!
先把每条路径都存进去,然后一个串一个串的找,找什么?
比如说我目前的01串是10110110011,我应该找一个什么样的去异或是最理想的?当然是找最接近01001001100的啦,为什么?因为异或出来明显是一串1嘛;
但是什么叫最接近?一定是得到的1最多么?
不一定,而是较大的那位最有优先权,因为这一位明显比后面的位分量都要足嘛,所以不要走入误区而想多;
好,最后我们捋一遍思路,首先,深搜求出某个点到每个点的XOR路径,然后把这些数都按二进制一位一位存到trie树里面,之后枚举点,一位一位地去找出哪两个点可以获得最大的XOR路径,这道题完美地走向结局。
还有一点,写得稍微简单一点,不然容易被卡时限
1 #pragma GCC optimize(3) 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #include<string> 6 #include<cstring> 7 #include<cstdlib> 8 #include<algorithm> 9 #include<bitset> 10 #define ms(a) memset(a,0,sizeof(a)) 11 using namespace std; 12 const int MAXN=33; 13 const int MAXM=100002; 14 int head[MAXN*10000],w1[MAXN*10000],w[MAXN*10000],v[MAXN*10000],nxt[MAXN*10000],trie[MAXN*MAXM][2]; 15 int xx,yy,zz,ans=0,tot=0,cnt=0; 16 bool vis[MAXN*10000]; 17 int n,m,k; 18 void add(int x,int y,int z) 19 { 20 v[++tot]=y;w[tot]=z; 21 nxt[tot]=head[x]; 22 head[x]=tot; 23 } 24 void dfs(int x) 25 { 26 for(int i=head[x];i!=-1;i=nxt[i]){ 27 int y=v[i]; 28 if(!vis[y]){ 29 vis[y]=true; 30 w1[y]= w[i] xor w1[x]; 31 dfs(y); 32 } 33 } 34 } 35 void insert(int x) 36 { 37 int now=0; 38 for(int i=30;i>=0;i--){ 39 int temp=x&(1<<i)?1:0; 40 if(!trie[now][temp]){ 41 trie[now][temp]=++cnt; 42 } 43 now=trie[now][temp]; 44 } 45 } 46 int find(int x) 47 { 48 int now=0,w=0; 49 for(int i=30;i>=0;i--){ 50 int temp=x&(1<<i)?1:0; 51 if(trie[now][!temp]){ 52 w|=(1<<i);now=trie[now][!temp]; 53 } 54 else now=trie[now][temp]; 55 } 56 return w; 57 } 58 int main() 59 { 60 while(~scanf("%d",&n)){ 61 ms(vis);ms(trie);ms(w);ms(w1); 62 memset(head,-1,sizeof(head));tot=ans=cnt=0; 63 int x,y,z; 64 for(int i=1;i<n;i++){ 65 scanf("%d%d%d",&x,&y,&z); 66 add(x,y,z);add(y,x,z); 67 } 68 dfs(x); 69 for(int i=0;i<n;i++){ 70 insert(w1[i]); 71 ans=max(ans,find(w1[i])); 72 } 73 cout<<ans<<endl; 74 } 75 return 0; 76 }