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 }
View Code

 

posted @ 2017-08-10 06:59  Blue233333  阅读(250)  评论(0编辑  收藏  举报