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行,每行一个整数,表示异或值

 

输入输出样例

输入样例#1:
5
1 4 9644
2 5 15004
3 1 14635
5 3 9684
3
2 4
5 4
1 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  }*/ 
View Code

 

posted @ 2018-09-29 17:11  cellur925&Chemist  阅读(142)  评论(0编辑  收藏  举报