BZOJ1954: Pku3764 The xor-longest Path
给定一棵n<=100000个点的带权树,求树上最长的异或和路径。
“求树上最xx路径”“统计树上xx路的方案数”,本来想用点分的,然后想处理出根节点到每个点的亦或路径时如何统计答案避免判重,突然发现:根节点到A的路径亦或根节点到B的路径就是A到B的路径!
于是预处理(用bfs,避免爆栈)出根节点到每个节点的亦或路径之后,问题变成在这个长度n的数组中选两个数使亦或和最大。
先把每个数按二进制位从高到低丢进Trie,然后
方法一:枚举每个数,在Trie上每一位尽量往反方向跳,比如数1010,就尽量跳成0101,除非某一位没有反方向不得不跳同方向,边跳边更新答案。
方法二:开两个指针,从Trie根节点直接往下走,能走反方向就走反方向,比如p往0走q就往1走,如果出现多种“反方向”的选择,就每种选择都跑一遍取Max。
下面是方法二代码。
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std; 7 8 int n; 9 #define maxn 100011 10 #define LL long long 11 int x,y,v; 12 struct Edge{int to,v,next;}; 13 int num[maxn],lnum=0; 14 int que[maxn],head,tail; 15 struct Tree 16 { 17 int first[maxn];Edge edge[maxn*2];int le; 18 Tree() {memset(first,0,sizeof(first));le=2;} 19 void in(int x,int y,int v) 20 { 21 Edge &e=edge[le]; 22 e.to=y;e.v=v; 23 e.next=first[x]; 24 first[x]=le++; 25 } 26 void insert(int x,int y,int v) 27 { 28 in(x,y,v); 29 in(y,x,v); 30 } 31 void bfs(int x) 32 { 33 que[head=(tail=1)-1]=x; 34 memset(num,-1,sizeof(num)); 35 num[x]=0; 36 while (head!=tail) 37 { 38 const int now=que[head++],d=num[now]; 39 for (int i=first[now];i;i=edge[i].next) 40 if (num[edge[i].to]==-1) 41 { 42 num[edge[i].to]=d^edge[i].v; 43 que[tail++]=edge[i].to; 44 } 45 } 46 } 47 }t; 48 struct Trie 49 { 50 int ch[maxn*25][2],cnt[maxn*25]; 51 int size; 52 Trie() 53 { 54 size=0; 55 ch[0][0]=ch[0][1]=0; 56 cnt[0]=0; 57 } 58 void insert(int v) 59 { 60 int now=0; 61 bool bin[33]; 62 for (int i=1;i<=31;i++) 63 { 64 bin[i]=v&1; 65 v>>=1; 66 } 67 for (int i=31;i>=1;i--) 68 { 69 if (!ch[now][bin[i]]) 70 { 71 size++; 72 ch[size][0]=ch[size][1]=0; 73 ch[now][bin[i]]=size; 74 cnt[size]=0; 75 } 76 now=ch[now][bin[i]]; 77 } 78 cnt[now]++; 79 } 80 int ans; 81 int play(int p,int q,int dep) 82 { 83 if (!dep) return 0; 84 int base=1<<(dep-1); 85 if (!ch[p][1]) 86 { 87 if (!ch[q][1]) return play(ch[p][0],ch[q][0],dep-1); 88 else return base^play(ch[p][0],ch[q][1],dep-1); 89 } 90 if (!ch[p][0]) 91 { 92 if (!ch[q][0]) return play(ch[p][1],ch[q][1],dep-1); 93 else return base^play(ch[p][1],ch[q][0],dep-1); 94 } 95 if (!ch[q][0]) return base^play(ch[p][0],ch[q][1],dep-1); 96 if (!ch[q][1]) return base^play(ch[p][1],ch[q][0],dep-1); 97 if (p==q) return base^play(ch[p][0],ch[q][1],dep-1); 98 return max(base^play(ch[p][0],ch[q][1],dep-1),base^play(ch[p][1],ch[q][0],dep-1)); 99 } 100 }trie; 101 int main() 102 { 103 scanf("%d",&n); 104 for (int i=1;i<n;i++) 105 { 106 scanf("%d%d%d",&x,&y,&v); 107 t.insert(x,y,v); 108 } 109 t.bfs(n/2); 110 for (int i=1;i<=n;i++) trie.insert(num[i]); 111 trie.ans=trie.play(0,0,31); 112 printf("%d\n",trie.ans); 113 return 0; 114 }