洛谷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。
代码
#include<cstdio>
#define MAXN 100005
using namespace std;
inline int read(){
int num=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')num=num*10+ch-48,ch=getchar();
return num*f;
}
inline void write(int x){
if(x>9)write(x/10);
putchar(x%10+48);x/=10;
}
inline void swap(int* a,int* b){int t = *a;*a=*b;*b=t;}
int anc[MAXN][20];
int d[MAXN],dis[MAXN],head[MAXN];
struct Node{
int next,v,w;
}G[MAXN<<1];
int N,M;
int tot = 0;
inline void add(int u,int v,int w){
G[++tot].v=v;G[tot].w=w;G[tot].next=head[u];head[u]=tot;
}
inline void dfs(int rt,int fa){
for(register int i=head[rt];i;i=G[i].next){
int v = G[i].v;if(v==fa)continue;
d[v]=d[rt]+1;anc[v][0]=rt;dis[v]=G[i].w^dis[rt];
dfs(v,rt);
}
}
inline void find_Node_father(){
for(register int j=1;j<=17;++j)
for(register int i=1;i<=N;++i)anc[i][j]=anc[anc[i][j-1]][j-1];
}
inline int LCA(int u,int v){
if(d[u]<d[v])swap(&u,&v);
for(register int i=17;i>=0;--i)
if(d[anc[u][i]]<=d[v])u=anc[u][i];
if(u==v)return u;
for(register int i=17;i>=0;--i)
if(anc[u][i]!=anc[v][i])u=anc[u][i],v=anc[v][i];
return anc[u][0];
}
int main(){
N = read();
for(register int i=1;i<N;++i){
int u,v,w;
u=read();v=read();w=read();
add(u,v,w);add(v,u,w);
}
dis[1]=0;d[1]=0;
dfs(1,0);
find_Node_father();
M = read();
for(register int i=0;i<M;++i){
int u=read();int v=read();
int lca = LCA(u,v);
write((dis[lca]^dis[u])^(dis[lca]^dis[v]));putchar('\n');
}
return 0;
}