• P4551 最长异或路径 Trie经典应用 bitset应用


    P4551 最长异或路径 Trie经典应用 bitset应用

    bitset使用

    一个长度为(N)的bitset下标编号为([0,N))

    进行单点修改时,可以直接访问位置并且赋值

    [s[pos] = x; ]

    bitset重载了<< 和 >> 输入输出流,可以使用cin或者cout输入输出一个bitset的所有元素

    注意bitset的输出方式

    std::cin >> s;							// 1101
    std::cout << s << std::endl;			// 000001101
    

    bitset可以转化为string型,unsigned long long型,函数名to_string(),to_ullong()

    成员函数

    reset

    s.reset();

    将容器清空

    set

    s.reset();
    s.set()				//11111111
    s.set(3,false)		//11110111
    s.set(3)			//11111111
    

    test

    test有一个参数pos,返回一个bitset内第pos位的值。

    any

    bitset有一个成员函数为any,返回一个布尔量。若bitset内部存在一位的值为1,则返回true,否则返回false:

    s.clear();
    bool k = s.any();			//k is false
    s[1] = true;
    k = s.any()					//k is true
    

    count

    count返回一个bitset内1的个数,是一个无符号整形:

    s.reset();
    int k = s.count();				// k is 0					
    s[1] = true;
    k = s.count();					// k is 1
    

    题意

    给定一棵树和边权,求两点(u,v)使得两点的路径异或值最大。

    [1 leq n leq 1e5\ 0 leq w leq 2^{31} ]

    分析

    我们发现两点的路径异或等于两点分别到根的路径异或值相异或(LCA到根的异或抵消)

    那么只要DFS出了根到该点的异或值,问题就转化为了(n)个值,问其中异或值最大的两个值的异或,这是经典的Trie上贪心异或问题。

    只需要把每个数从高位开始贪心插入Trie,枚举每个数然后再Trie上贪心走反的边即可。

    复杂度O(w*n)

    代码

    struct Trie{
    	int now = 1;
    	int ch[100000 * 31][2];
    	//vector<vector<int>> ch;
    	//Trie():ch(100000 * 31,vector<int>(2,0)) {}
    	bitset<32> st;
    	void insert(int x){
    		st.reset();
    		int cnt = 0;
    		int cur = 1;
    		while(x){
    			st.set(cnt,x % 2);
    			x /= 2;
    			cnt++;
    		}
    		for(int i = 30;i >= 0;i--){
    			if(ch[cur][st.test(i)] == 0) 
    				ch[cur][st.test(i)] = ++now;
    			cur = ch[cur][st.test(i)];
    		}
    	}
    	int get(int x){
    		st.reset();
    		int cnt = 0;
    		int cur = 1;
    		int res = 0;
    		while(x){
    			st.set(cnt,x % 2);
    			x /= 2;
    			cnt++;
    		}
    		for(int i = 30;i >= 0;i--){
    			if(ch[cur][!st.test(i)])  
    				cur = ch[cur][!st.test(i)],res |= (1 << i);
    			else 
    				cur = ch[cur][st.test(i)];
    		}		
    		return res;
    	}
    };
    
    int d[100005];
    vector<pii> e[100005];
    
    void dfs(int u,int fa){
    	for(auto v:e[u]) {
    		if(v.fi == fa) continue;
    		d[v.fi] = d[u] ^ v.se; 
    		dfs(v.fi,u);
    	}
    }
    
    Trie t;
    
    int main(){
    	int n = rd();
    	for(int i = 0;i < n - 1;i++){
    		int x = rd();
    		int y = rd();
    		int w = rd();
    		e[x].push_back(make_pair(y,w));
    		e[y].push_back(make_pair(x,w));
    	}
    	dfs(1,0);
    	t.insert(d[1]);
    	int ans = -1;
    	for(int i = 2;i <= n;i++){
    		ans = max(ans,t.get(d[i]));
    		t.insert(d[i]);
    	}
    	cout << ans;
    }
    
    
  • 相关阅读:
    obj,lib,dll,exe
    .net连接access数据库 关键字引起的 语句的语法错误
    XSS攻击与防御
    location.href和location.replace和location.reload的不同(location.replace不记录历史)
    C++中头文件包含问题
    SqlServerExpress2005 自动备份
    在SQL Server 的使用过程中,发现几个很有用,但不太常用
    双机镜像
    浅谈SQL Server identity列的操作方法
    镜像三机
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14540307.html
Copyright © 2020-2023  润新知