【洛谷P2420】让我们异或吧
题目描述
异或是一种神奇的运算,大部分人把它总结成不进位加法.
在生活中…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+数学
分析:
这道题乍眼一看感觉是带权值的最近公共祖先问题,但粗略计算后发现会超时,进一步分析,得到一些有关异或的规律,然后这就是一道暴力的题目。
引用一些大佬的资料:
根据题目中对“异或”的定义,我们可以得出异或的真值表,这里我们用a,b代表异或的两个元素,a^b代表a按位异或的值。
[code] a b a^b[/code]
[code]0
0
0[/code]
[code]0
1
1[/code]
[code]1
0
1[/code]
[code]1
1
0[/code]
我们发现,如果a==b,那么a^b就是0,否则式子的值就是1。
通过真值表,我们可以发现并证明异或的几个性质。
1.a^b==b^a
异或具有交换律
[code] a b a^b b^a[/code]
[code]0
0
0
0[/code]
[code]0
1
1
1[/code]
[code]1
0
1
1[/code]
[code]1
1
0
0[/code]
2.a^b^c==a^(b^c)
异或具有结合律
[code] a b c a^b^c a^(b^c)[/code]
[code]0
0
0
0
0[/code]
[code]0
0
1
1
1[/code]
[code]0
1
0
1
1[/code]
[code]0
1
1
0
0[/code]
[code]1
0
0
1
1[/code]
[code]1
0
1
0
0[/code]
[code]1
1
0
0
0[/code]
[code]1
1
1
1
1[/code]
3.a^a==0
异或自己是0
[code] a a^a[/code]
[code]0
0[/code]
[code]1
0[/code]
4.a^0=a
异或0还是0
[code] a a^0[/code]
[code]0
0[/code]
[code]1
1[/code]
由以上四点性质,我们可以推出:
a^b^b = a^(b^b)
[code] = a^0
= a[/code]
所以推出如下定理:
异或的逆运算是它本身!!!
讲一下对于本题的具体思路:对于这棵树,随意指定一个根节点,以此点来建树,维护每个点到根节点的距离,两个点u到v的树上路径一定为
u->lca(u,v)->v
第一个过程一定是一直向父亲节点前进,第二个过程一定是一直向儿子节点前进。
(lca(u,v)的定义为u,v的树上最近公共祖先)
那么最后查询的答案一定为
length[u]^length[v] anc^ length[lca(u,v)] anc^ length[lca(u,v)]
其中anc^为^的逆运算,由于之前已经推出anc^等价于^,而两次亦或的结果等价于原结果,所以最后的答案为:
length[u]^length[v]
此处不用考虑特判u或v是根节点的情况。
建树的时间复杂度为O(N),查询只需要O(1)的时间,最后程序的时间复杂度为O(N+M),空间复杂度为O(N)。
上代码:
#include<cstdio> #define maxn 100010 using namespace std; int n,m,tot,head[maxn],dis[maxn]; struct node { int nxt,to,val; }edge[maxn<<1]; bool vis[maxn]; int read() { int x=0,f=1; char c=getchar(); while (c<48||c>57) f=c=='-'?-1:1,c=getchar(); while (c>=48&&c<=57) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } void add(int c,int b,int a) { edge[++tot]=(node){head[a],b,c}; head[a]=tot; edge[++tot]=(node){head[b],a,c}; head[b]=tot; } int dfs(int u,int Xor) { dis[u]=Xor; vis[u]=1; for (int i=head[u];i;i=edge[i].nxt) if (!vis[edge[i].to]) dfs(edge[i].to,Xor^edge[i].val); } int main() { int i,j,k,u,v; n=read(); for (i=1;i<=n-1;i++) add(read(),read(),read()); m=read(); dfs(1,0); while (m--) printf("%d\n",dis[read()]^dis[read()]); return 0; }
- CONTEST221 洛谷9月月赛Div.2 -P2420 让我们异或吧
- 洛谷 [P2420] 让我们异或吧
- 洛谷 2420 让我们异或吧
- 洛谷 P2420 让我们异或吧 树形dp
- 洛谷P2420 让我们异或吧 树上差分 dfs
- 洛谷——P2420 让我们异或吧
- 洛谷 2420 让我们异或吧
- P2420 让我们异或吧
- P2420 让我们异或吧
- 01Trie树【p2420】 让我们异或吧
- AC日记——让我们异或吧 洛谷 P2420
- luogu2420 让我们异或吧
- luogu2420 让我们异或吧
- 洛谷P2420 让我们异或吧
- 让我们异或吧
- 【LCA】洛谷2420[让我们异或吧]题解
- P2420 让我们异或吧(倍增)
- luogu2420 让我们异或吧
- 洛谷P2420 让我们异或吧
- luogu2420 让我们异或吧