zoukankan      html  css  js  c++  java
  • GJGHFD的最小树 题解 [Trie树+启发式合并]

    GJGHFD的最小树

    Description:

    ​ 给定一棵(n)个结点的树,结点标号为 (0,1, · · · ,n−1) 并且树上每条边有一个权值 (w_i),你可以不断向这张图加入一条权值为任意非负整数的边,或者从图里删除一条边,但是在任意时刻以下条件都必须满足:

    1. 这张图是连通的.
    2. 对于这张图中的任意一个环,环上所有边的异或和必须为 (0) .

    求最终图中所有边权值和的最小值.

    Input:

    ​ 第一行一个整数 (n),表示树的大小.
    ​ 接下来 (n−1) 行,每行三个整数 (x, y, z),表示树中有一条连接结点 (x, y)的边,边权为 (z).

    Output:

    ​ 输出一行一个整数表示答案.

    Sample Input:

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

    Sample Output:

    7
    

    Hint:

    ​ 对于(20\%)的数据,(2 leq n leq 10)

    ​ 对于(50\%)的数据,(2 leq n leq 1000)

    ​ 对于(100\%)的数据,$ 2leq n leq 10^5.0 leq z < 2^{30}$

    ​ 时间限制: (1s)

    ​ 空间限制: (512M)

    题目分析:

    ​ 可以发现,当加入一条边((u, v))时,其边权一定等于原树中从(u)(v)边权的异或和. 如果我们赋予树上每个结点一个权值,使得任意两个相邻结点权值的异或等于连接他们的边的权值,那么原问题就转化为一个(xor)最小生成树了,使用启发式合并(+)字典树即可解决. 至于如何赋权,DFS 一遍将每个结点的权值设为从根到它路径上边权的异或和即可.

    ​ 代码如下(马蜂很丑,不喜勿喷)——

    #include<bits/stdc++.h>
    #define Tp template<typename T>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define maxn 100005
    #define inf 2147483647
    #define LL long long
    using namespace std;
    int n,tot,a[maxn],fir[maxn],son[maxn<<1],nxt[maxn<<1],w[maxn<<1],s[maxn*30],ch[maxn*30][2],pw[maxn];LL ans;
    inline void insert(int x){int now=0;for(register int i=29,to;i>=0;i--) to=((x>>i)&1),(!ch[now][to])&&(ch[now][to]=++tot),now=ch[now][to],s[now]++;}
    inline void add(int x,int y,int z){son[++tot]=y,nxt[tot]=fir[x],fir[x]=tot,w[tot]=z;}
    inline int dfs(int x,int y,int dep){
    	if(dep==31) return 0;int res=inf;if(ch[x][0]) if(ch[y][0]) res=min(res,dfs(ch[x][0],ch[y][0],dep+1));else res=min(res,dfs(ch[x][0],ch[y][1],dep+1)+pw[30-dep]);
    	if(ch[x][1]) if(ch[y][1]) res=min(res,dfs(ch[x][1],ch[y][1],dep+1));else res=min(res,dfs(ch[x][1],ch[y][0],dep+1)+pw[30-dep]);return res;
    }
    inline void solve(int x,int dep){
    	if(!x&&dep>1) return;solve(ch[x][0],dep+1),solve(ch[x][1],dep+1);if(!ch[x][0]||!ch[x][1]) return;
    	if(s[ch[x][0]]>s[ch[x][1]]) ans+=dfs(ch[x][1],ch[x][0],dep+1)+pw[30-dep];else ans+=dfs(ch[x][0],ch[x][1],dep+1)+pw[30-dep];
    }
    inline void get(int x,int fa){insert(a[x]);for(register int i=fir[x];i;i=nxt[i]) if(son[i]!=fa) a[son[i]]=(a[x]^w[i]),get(son[i],x);}
    class FileInputOutput
    {
    	private:
    		static const int S=1<<21;
    		#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
    		#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
    		char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
    	public:
    		FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
    		Tp inline void read(T& x)
    		{
    			x=0; char ch; while (!isdigit(ch=tc()));
    			while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
    		}
    		Tp inline void write(T x,const char& ch)
    		{
    			if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
    			while (ptop) pc(pt[ptop--]+48); pc(ch);
    		}
    		inline void flush(void)
    		{
    			fwrite(Fout,1,Ftop-Fout,stdout);
    		}
    		#undef tc
    		#undef pc
    }F;
    int main(){
    //	freopen("data.in","r",stdin);
    	F.read(n);pw[0]=1;for(register int i=1;i<=29;i++) pw[i]=(pw[i-1]<<1);
    	for(register int i=1,x,y,z;i<n;i++) F.read(x),F.read(y),F.read(z),add(x,y,z),add(y,x,z);tot=0;get(0,-1);
    	/*for(register int i=1;i<=n;i++) F.read(a[i]),insert(a[i]);*/solve(0,1);F.write(ans,'
    ');return F.flush(),0;
    }
    
  • 相关阅读:
    Linux 基础命令(一)转
    Django项目发布 环境部署(下)
    Django项目发布 环境部署(中)
    Django项目发布 环境部署(上)
    deepin linux 打开ssh服务
    虚拟机网卡重启
    centos7 mysql数据库安装和配置
    centos7 修改网络配置
    MySQL----view & transaction
    MySQL ----函数
  • 原文地址:https://www.cnblogs.com/jiangxuancheng/p/14208689.html
Copyright © 2011-2022 走看看