• 01Trie树【p2420】 让我们异或吧


    Description

    异或是一种神奇的运算,大部分人把它总结成不进位加法.

    在生活中…xor运算也很常见。比如,对于一个问题的回答,是为1,否为0.那么:

    (A是否是男生 )xor( B是否是男生)=A和B是否能够成为情侣

    好了,现在我们来制造和处理一些复杂的情况。比如我们将给出一颗树,它很高兴自己有N个结点。树的每条边上有一个权值。我们要进行M次询问,对于每次询问,我们想知道某两点之间的路径上所有边权的异或值。

    Input

    输入文件第一行包含一个整数N,表示这颗开心的树拥有的结点数,以下有N-1行,描述这些边,每行有3个数,u,v,w,表示u和v之间有一条权值为w的边。接下来一行有一个整数M,表示询问数。之后的M行,每行两个数u,v,表示询问这两个点之间的路径上的权值异或值。

    Output

    输出M行,每行一个整数,表示异或值

     很明显,树上问题求解两节点间的问题,直接考虑到(LCA)

    我们记录(dis[u])代表从(u)到根节点的路径异或值

    那么我们可以在(dfs)预处理倍增数组的时候预处理出来我们的(dis)数组.

    (dis)数组有什么用?

    如图,我们询问节点(x->y)的路径异或值。

    此时已知(dis[x])(dis[y]),根据(xor)的性质。

    可得(x->y)的路径异或值为((dis[x] xor dis[lca_{x,y}]) xor (dis[y] xor dis[lca_{x,y}]))

    直接求解即可

    代码

    #include<cstdio>
    #include<cctype>
    #include<algorithm> 
    #define N 100008
    #define R register
    using namespace std;
    inline void in(int &x)
    {
    	int f=1;x=0;char s=getchar();
    	while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    	while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    	x*=f;
    }
    int depth[N],n,m,dis[N],f[N][21],head[N],tot;
    struct cod{int u,v,w;}edge[N<<2];
    inline void add(int x,int y,int z)
    {
    	edge[++tot].u=head[x];
    	edge[tot].v=y;
    	edge[tot].w=z;
    	head[x]=tot;
    }
    void dfs(int u,int fa,int w)
    {
    	depth[u]=depth[fa]+1;dis[u]=dis[fa]^w;
    	for(R int i=1;(1<<i)<=depth[u];i++)
    		f[u][i]=f[f[u][i-1]][i-1];
    	for(R int i=head[u];i;i=edge[i].u)
    	{
    		if(edge[i].v==fa)continue;
    		dfs(edge[i].v,u,edge[i].w);
    	}
    }
    inline int lca(int x,int y)
    {
    	if(depth[x]>depth[y])swap(x,y);
    	for(R int i=17;i>=0;i--)
    		if(depth[x]+(1<<i)<=depth[y])
    			y=f[y][i];
    	if(x==y)return x;
    	for(R int i=17;i>=0;i--)
    	{
    		if(f[x][i]==f[y][i])continue;
    		x=f[x][i],y=f[y][i];
    	}
    	return f[x][0];
    }
    int main()
    {
    	in(n);
    	for(R int i=1,x,y,z;i<n;i++)
    	{
    		in(x),in(y),in(z);
    		add(x,y,z);add(y,x,z);
    	}
    	dfs(1,0,0);
    	in(m);
    	for(R int x,y,la;m;m--)
    	{
    		in(x),in(y);
    		if(x==y)
    		{
    			puts("0");
    			continue;
    		}
    		la=lca(x,y);
    		printf("%d
    ",(dis[x]^dis[la])^(dis[y]^dis[la]));
    	}
    }
    

    不太理解为什么要建双向边,

    如果有大佬懂的话能否告知蒟蒻我 qwq

  • 相关阅读:
    剑指OFFER之合并有序链表(九度OJ1519)
    剑指OFFER之反转链表(九度OJ1518)
    剑指OFFER之链表中倒数第k个节点(九度OJ1517)
    一分钟教你在博客园中制作自己的动态云球形标签页
    剑指OFFER之调整数组顺序使奇数位于偶数前面找(九度OJ1516)
    剑指OFFER之打印1到最大的N位数(九度OJ1515)
    剑指OFFER之矩形覆盖(九度OJ1390)
    剑指OFFER之数值的整数次方(九度OJ1514)
    剑指OFFER之变态跳台阶(九度OJ1389)
    剑指OFFER之二进制中1的个数(九度OJ1513)
  • 原文地址:https://www.cnblogs.com/-guz/p/9763042.html
Copyright © 2020-2023  润新知