zoukankan      html  css  js  c++  java
  • 题解 P4551 【最长异或路径】

    题意

    给定一棵 (n) 个点的带权树,结点下标从 (1) 开始到 (N) 。寻找树中找两个结点,求最长的异或路径。

    异或路径指的是指两个结点之间唯一路径上的所有边权的异或。

    解法

    • 先预处理出从根结点到所有结点的路径上的 (xor) 值,显然 (d(x) = d(fa)) ^ (val(fa o x))

    • 又因为异或有一性质 (a) ^ (a=0) ,所以可以发现从 (x)(y) 的异或路径就是 (d(x)) ^ (d(y)),因为 (d(1)) ^ (d(x-1)) 经过两次计算相抵消了。

    • 然后问题就转化了在 (1 le i,jle n) 中找到最大的 (d(i)) ^ (d(j)),把每个数看做一个二进制01串,建立一棵01字典树,利用贪心的思想每次找与当前位相反的结点即可。

    代码

    #include <iostream>
    #include <algorithm>
    #define M 200070
    #define N 5000070
    
    using namespace std;
    
    struct Edge
    {
    	int to,nxt,w;
    }e[M];
    int n,ans,cnt,tot;
    int d[M],head[M],nxt[N][2];
    
    void add(int from,int to,int val){
    	e[++cnt].to=to;
    	e[cnt].w=val;
    	e[cnt].nxt=head[from];
    	head[from]=cnt;
    }
    
    void dfs(int x,int fa){
    	for(int i=head[x];i;i=e[i].nxt){
    		int v=e[i].to;
    		if(v==fa) continue;
    		d[v]=d[x]^e[i].w;
    		dfs(v,x);
    	}
    }
    
    void insert(int x){
    	int c=0,op;
    	for(int i=31;i>=0;--i){
    		op=((x>>i)&1);
    		if(!nxt[c][op])
    			nxt[c][op]=++tot;
    		c=nxt[c][op];
    	}
    }
    
    int query(int x){
    	int c=0,sum=0,op;
    	for(int i=31;i>=0;--i){
    		op=((x>>i)&1);
    		if(nxt[c][op^1])
    			c=nxt[c][op^1],sum=sum<<1|1;
    		else
    			c=nxt[c][op],sum=sum<<1;
    	}
    	return sum;
    }
    
    int main(){
    	cin>>n;
    	for(int i=1;i<n;++i){
    		int u,v,w;
    		cin>>u>>v>>w;
    		add(u,v,w);
    		add(v,u,w);
    	}
    	dfs(1,0);
    	insert(d[1]);
    	for(int i=2;i<=n;++i){
    		ans=max(ans,query(d[i]));
    		insert(d[i]);
    	}
    	cout<<ans<<endl;
    }
    

    时间复杂度为(Theta (31*N))

  • 相关阅读:
    jquery.autocomplete.js 插件的自定义搜索规则
    经测试可用的汉字转拼音及汉字取首字母
    微信小程序UI学习
    微信小程序的生命周期和APP对象的使用
    微信小程序的配置详解
    微信小程序事件
    视图和渲染
    微信小程序<一>
    JS实战篇
    获取重复字符串的range,设置attributedText
  • 原文地址:https://www.cnblogs.com/Niuwadiandian/p/13944605.html
Copyright © 2011-2022 走看看