zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第五场)B题Graph(01字典树)

    2020牛客暑期多校训练营(第五场)B题Graph(01字典树)

    Graph

    题意:给你一个树与每个边的权值,你可以进行任意操作,加边或删边,加边的值为其连成环的其他边的异或,删边后要保证图连通,求所有边和的最小值。

    题解:对于任意两点,都可以求出其边,要么题目给你了,要么可以通过异或算出来,即给了你一个完全图,然后求一个最小生成树既可。所有点间的边显然存不下,但是存在点上就可以用O(n)的内存用异或公式求出任意边,所以我们可以把边的权值转移为点上的权值,点的权值为其前缀异或;

    如题目样例:

    6
    0 1 1
    1 2 4
    1 3 3
    0 4 5
    0 5 2

    转移为点上权值后为:0 1 5 2 5 2

    然后任意两点间的边为两点的异或值

    之后就是求一个xor的最小生成树既可,这边推荐一个大佬的博客,写得很好

    感谢大佬

    方法是在字典树上求最小生成树,将所有点权放进字典树,对于字典树每一层,其为0的一端必然要与1的一端连接(如果都有点),记录枚举为0一端的所有权值与为1一端的所有权值xor(n方超时)的最小答案,这里优化,将为0一端的所有权值进为1一端的字典树中,设第i次枚举的值为x,对于其二进制的每一位在字典树中尽量走与他相同的路既可最优,时间从n方降为nlogn,层数为30,即总复杂度为O(30 * n * logn),说的有点抽象,这一段看不太懂的话可以去看下那个大佬的博客,讲的很好。

    #include<iostream>
    #include<vector>
    using namespace std;
    #define ll long long
    const ll N=200007;
    ll maxn=1e18+7;
    ll n,a[N],cnt,p,ans,u,v,c;
    ll vis[N];
    struct madoka{
    	ll l;
    	ll r;
    }ma[30*N];
    vector<ll>ho;
    vector<pair<ll,ll> >us[N];
    void go(ll p,ll c){
    	vis[p]=1;
    	a[p]=c;
    
    	for(int i=0;i<us[p].size();i++){
    		if(vis[us[p][i].first]==0){
    			go(us[p][i].first,c^us[p][i].second);
    		}
    	}
    }
    void up(ll &p,ll z,ll h){
    	if(!p){
    		p=++cnt;
    	}
    	if(h==-1)return;
    	if(z>=(1<<h)){
    		up(ma[p].r,z-(1<<h),h-1);
    	}
    	else{
    		up(ma[p].l,z,h-1);
    	}
    }
    ll qry(ll z,ll p,ll h){
    	if(h==-1)return 0;
    	int lin=z&(1<<h);
    	if(lin){
    		if(ma[p].r){
    			return qry(z,ma[p].r,h-1);
    		}
    		else{
    			return (1<<h)+qry(z,ma[p].l,h-1);
    		}
    	}
    	else{
    		if(ma[p].l){
    			return qry(z,ma[p].l,h-1);
    		}
    		else{
    			return (1<<h)+qry(z,ma[p].r,h-1);
    		}
    	}
    }
    ll dfs(vector<ll>ho,ll p,ll h){
    	if(p==0)return 0;
    	vector<ll>lp,rp;
    	ll ans=maxn;
    	ll lim=(1<<h);
    	for(int i=0;i<ho.size();i++){
    		if(ho[i]&lim){
    			rp.push_back(ho[i]);
    		}
    		else{
    			lp.push_back(ho[i]);
    		}
    	}
    	if(lp.size()&&rp.size()){
    		for(int i=0;i<rp.size();i++){
    			ans=min(ans,(1<<h)+(ll)qry(rp[i],ma[p].l,h-1));
    		}
    	}
    	else{
    		ans=0;
    	}
    	return ans+dfs(lp,ma[p].l,h-1)+dfs(rp,ma[p].r,h-1);
    }
    int main(){
    	scanf("%lld",&n);
    	for(int i=1;i<n;i++){
    		scanf("%lld%lld%lld",&u,&v,&c);
    		us[u].push_back({v,c});
    		us[v].push_back({u,c});
    	}
    	go(0,0);
    	for(int i=0;i<n;i++){
    		ho.push_back(a[i]);
    		up(p,a[i],30);
    	}
    	printf("%lld
    ",dfs(ho,1,30));
    }
    
    
  • 相关阅读:
    JAVA复习笔记之GC部分
    elasticsearch学习笔记--原理介绍
    JavaScript--Array数组jion方法使用
    MyBatis探究-----缓存机制详解
    C#---- Winform控件PictureBox详解
    Mybatis探究-----一对一、一对多关联查询
    C#-----CancellationTokenSource取消线程
    MyBatis探究-----接口类映射XML文件中符号$和#的区别
    C#-----定时器的几种实现
    eclipse如何在不联网的情况下引入dtd约束文件
  • 原文地址:https://www.cnblogs.com/whitelily/p/13382743.html
Copyright © 2011-2022 走看看