• 最长路径异或和


    题目大意

    给定一棵边权树, 要求一条两个点之间的最短路径, 使得路径上所有边的权值的异或最大.

    题解

    考虑异或的性质:

    • 交换律(a oplus b = b oplus a)
    • 结合律((a oplus b) oplus c = a oplus (b oplus c))
    • 消去率(a oplus b = a oplus c oplus b oplus c)

    所以我们发现, 假设(anc)(u)(v)的祖先, (u)(v)分别是路径的两端, 则(u o anc o v = (root o anc o u) oplus (root o anc o v))

    DFS一次, 到达每个点的时候都在trie树上找最大异或值即可.

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    
    const int N = (int)1e5;
    
    namespace Zeonfai
    {
    	inline int getInt()
    	{
    		int a = 0, sgn = 1;
    		char c;
    		while(! isdigit(c = getchar()))
    			if(c == '-')
    				sgn *= -1;
    		while(isdigit(c))
    			a = a *10 + c - '0', c = getchar();
    		return a * sgn;
    	}
    }
    
    struct trieTree
    {
    	struct node
    	{
    		node *suc[2];
    
    		inline node()
    		{
    			suc[0] = suc[1] = NULL;
    		}
    	};
    	
    	node *rt, *lst;
    
    	inline void initialize()
    	{
    		rt = new node;
    	}
    
    	inline void _insert(int k)
    	{
    		node *u = lst->suc[k];
    		if(lst->suc[k] == NULL)
    			lst->suc[k] = new node;
    		lst = lst->suc[k];
    	}
    	
    	inline void insert(int w)
    	{
    		lst = rt;
    		for(int i = 30; ~ i; -- i)
    			_insert(w >> i & 1);
    	}
    
    	inline int query(int w)
    	{
    		int res = 0;
    		node *u = rt;
    		for(int i = 30; ~ i; -- i)
    		{
    			int k = w >> i & 1;
    			if(u->suc[k ^ 1] != NULL)
    				u = u->suc[k ^ 1], res += 1 << i;
    			else
    				u = u->suc[k];
    		}
    		return res;
    	}
    }trie;
    
    int ans = 0;
    
    struct tree
    {	
    	struct edge
    	{
    		int v, w, nxt;
    	}edg[N << 1];
    	
    	int tp;
    	int hd[N + 1];
    	
    	inline void initialize()
    	{
    		tp = 0;
    		memset(hd, -1, sizeof(hd));
    	}
    	
    	inline void addEdge(int u, int v, int w)
    	{
    		edg[tp].v = v, edg[tp].w = w, edg[tp].nxt = hd[u];
    		hd[u] = tp ++;
    	}
    	
    	inline void DFS(int u, int pre, int w)
    	{
    		trie.insert(w);
    		ans = std::max(ans, trie.query(w));
    		for(int p = hd[u]; ~ p; p = edg[p].nxt)
    			if(edg[p].v ^ pre)
    				DFS(edg[p].v, u, w ^ edg[p].w);
    	}
    }org;
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("XSY2340.in", "r", stdin);
    	#endif
    	using namespace Zeonfai;
    	int n = getInt();
    	org.initialize();
    	for(int i = 1; i < n; ++ i)
    	{
    		int u = getInt(), v = getInt(), w = getInt();
    		org.addEdge(u, v, w), org.addEdge(v, u, w);
    	}
    	trie.initialize();
    	org.DFS(1, -1, 0);
    	printf("%d
    ", ans);
    }
    
  • 相关阅读:
    工作流
    工作流管理系统
    Domino(群组工作软件)
    Integer与int的区别(转)
    Java NIO和IO的区别(转)
    String、StringBuffer与StringBuilder之间区别(转)
    JAVA 是否会发生内存泄露(转)
    Java关键字final、static使用总结(转)
    数据结构中常见的树(BST二叉搜索树、AVL平衡二叉树、RBT红黑树、B-树、B+树、B*树)(转)
    Java多线程:用三个线程控制循环输出10次ABC
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7114834.html
Copyright © 2020-2023  润新知