luogu P2420 让我们异或吧!【假LCA真搜索】
想念我们的杨乐老师!
题目描述
异或是一种神奇的运算,大部分人把它总结成不进位加法.
在生活中…xor运算也很常见。比如,对于一个问题的回答,是为1,否为0.那么:
(A是否是男生 )xor( B是否是男生)=A和B是否能够成为情侣
好了,现在我们来制造和处理一些复杂的情况。比如我们将给出一颗树,它很高兴自己有N个结点。树的每条边上有一个权值。我们要进行M次询问,对于每次询问,我们想知道某两点之间的路径上所有边权的异或值。
输入输出格式
输入格式:
输入文件第一行包含一个整数N,表示这颗开心的树拥有的结点数,以下有N-1行,描述这些边,每行有3个数,u,v,w,表示u和v之间有一条权值为w的边。接下来一行有一个整数M,表示询问数。之后的M行,每行两个数u,v,表示询问这两个点之间的路径上的权值异或值。
输出格式:
输出M行,每行一个整数,表示异或值
输入输出样例
5 1 4 9644 2 5 15004 3 1 14635 5 3 9684 3 2 4 5 4 1 1
975 14675 0
说明
对于40%的数据,有1 ≤ N,M ≤ 3000;
对于100%的数据,有1 ≤ N ,M≤ 100000。
(我们亲爱的杨乐老师)在讲图论时,讲到了这道“LCA的思想”的题目。然后Chemist就中毒了hhhhh。
其实跟LCA并没有什么关系,对这棵树进行一边BFS/DFS就可以轻松过。
然而我太蒟了,DFS/BFS都打不好......
我们先来搞一搞xor的性质。
一位luogu dalao @hsfzLZH1 慷慨地做了如下总结:
根据题目中对“异或”的定义,我们可以得出异或的真值表,这里我们用a,b代表异或的两个元素,a^b代表a按位异或的值。
a b a^b
0 0 0
0 1 1
1 0 1
1 1 0
我们发现,如果a==b,那么a^b就是0,否则式子的值就是1。
通过真值表,我们可以发现并证明异或的几个性质。
1.a^b==b^a
异或具有交换律
a b a^b b^a
0 0 0 0
0 1 1 1
1 0 1 1
1 1 0 0
2.a^b^c==a^(b^c)
异或具有结合律
a b c a^b^c a^(b^c)
0 0 0 0 0
0 0 1 1 1
0 1 0 1 1
0 1 1 0 0
1 0 0 1 1
1 0 1 0 0
1 1 0 0 0
1 1 1 1 1
3.a^a==0
异或自己是0
a a^a
0 0
1 0
4.a^0=a
异或0还是0
a a^0
0 0
1 1
由以上四点性质,我们可以推出:
a^b^b = a^(b^b)
= a^0
= a
所以推出如下定理:
异或的逆运算是它本身!!!
Update
这坑太大 填不动了 找了一个dalao的博客
https://www.cnblogs.com/BCOI/p/8591140.html
My code
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m,tot; 4 int head[200009]; 5 int xxor[200009],visit[200009]; 6 struct node{ 7 int to,val,next; 8 }edge[200009]; 9 queue<int>q; 10 void add(int x,int y,int z) 11 { 12 edge[++tot].to=y; 13 edge[tot].val=z; 14 edge[tot].next=head[x]; 15 head[x]=tot; 16 } 17 void bfs() 18 { 19 //queue<int>q; 20 q.push(1); 21 visit[1]=1; 22 while(!q.empty()) 23 { 24 int x=q.front(); 25 q.pop(); 26 for(int i=head[x];i;i=edge[i].next) 27 { 28 int y=edge[i].to; 29 if(visit[y]) continue; 30 visit[y]=1; 31 xxor[y]=xxor[x]^edge[i].val; 32 q.push(y); 33 } 34 } 35 } 36 int main() 37 { 38 scanf("%d",&n); 39 for(int i=1;i<=n-1;i++) 40 { 41 int u=0,v=0,w=0; 42 scanf("%d%d%d",&u,&v,&w); 43 add(u,v,w); 44 add(v,u,w); 45 } 46 bfs(); 47 scanf("%d",&m); 48 //for(int i=1;i<=6;i++) cout<<xxor[i]<<endl; 49 for(int i=1;i<=m;i++) 50 { 51 int u=0,v=0,ans=0; 52 scanf("%d%d",&u,&v); 53 printf("%d\n",xxor[u]^xxor[v]); 54 } 55 return 0; 56 } 57 /*#include<iostream> 58 using namespace std; 59 int n; 60 int main() 61 { 62 int a=0,b=0,x=0; 63 cin>>a>>b; 64 x=a^b; 65 cout<<x; 66 return 0; 67 }*/