题目
宫水三叶有一棵树,这是一棵大小为 n n n 的树,点从 0 0 0 开始编号。
树有 n − 1 n-1 n−1 条边,每条边可以用三个数 ( x i , y i , w i ) (x_i,y_i,w_i) (xi,yi,wi) 来描述,表示连接了 x i , y i x_i,y_i xi,yi 的权值为 w i w_i wi 的边。
宫水三叶想要改造这棵树。她可以做以下两种操作:
- 加入一条边 ( x , y , w ) (x,y,w) (x,y,w) 。图中可以已经出现连接 ( x , y ) (x,y) (x,y) 的边,即允许有重边。但是三叶需要保证加完边后的图任意一个环的边的异或和都为 0 0 0 。
- 删除图中的一条边。但是三叶需要保证删除完的图联通。
特别注意的是,对于一个 n n n 个点 n − 1 n-1 n−1 条边的连通图是不存在环的,这样一定满足所有环的异或值都为 0 0 0 的限制。
三叶可以重复进行操作,她想知道她最后改造出来的图的边权和最小是多少。
数据范围
本题采用捆绑测试。
对于所有数据,满足 2 ≤ n ≤ 1 0 5 , 0 ≤ x i , y i < n , x i ≠ y i , 0 ≤ w i < 2 30 2\le n \le 10^5,0\le x_i,y_i < n,x_i\neq y_i,0\le w_i <2^{30} 2≤n≤105,0≤xi,yi<n,xi=yi,0≤wi<230。
子任务编号 | n n n | w i w_i wi | 分值 |
---|---|---|---|
1 1 1 | ≤ 500 \le 500 ≤500 | < 2 30 <2^{30} <230 | 20 20 20 |
2 2 2 | ≤ 5000 \le 5000 ≤5000 | < 2 30 <2^{30} <230 | 25 25 25 |
3 3 3 | ≤ 1 0 5 \le 10^5 ≤105 | < 2 12 <2^{12} <212 | 25 25 25 |
4 4 4 | ≤ 1 0 5 \le 10^5 ≤105 | < 2 30 <2^{30} <230 | 30 30 30 |
题解
考虑把
(
i
,
j
)
(i,j)
(i,j)连起来,其代价为
(
i
,
j
)
(i,j)
(i,j)在树上之间路径的权值和,所以我们可以在把他建成完成图(不需要真的建),然后在上面跑最小生成树即可。
至于跑最小生成树这一块,我们将其放进01trie树里贪心即可,深度越深的异或和一定越小。
代码
#include<iostream>
#include<vector>
using namespace std;
vector<int> X;
int n,tot,cnt,root,head[100010],to[200010],w[200010],nxt[200010],ch[2000010][2];
void adde(int u,int v,int W)
{
nxt[++tot]=head[u],to[tot]=v,w[tot]=W,head[u]=tot;
}
void dfs(int x,int fa)
{
for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa) X[to[i]-1]=X[x-1]^w[i],dfs(to[i],x);
}
void addt(int &p,int x,int w)
{
if(!p) p=++cnt,ch[p][0]=ch[p][1]=0;
if(w<0) return;
addt(ch[p][(x>>w)&1],x,w-1);
}
long long ask(int p,int x,int w)
{
if(w<0) return 0;
if(ch[p][(x>>w)&1]) return ask(ch[p][(x>>w)&1],x,w-1);
return ask(ch[p][!((x>>w)&1)],x,w-1)+(1ll<<w);
}
long long js(vector<int> X,int w)
{
if(w<0||X.empty()) return 0;
vector<int> _1,_0;
_1.clear(),_0.clear();
for(int i=0,nq=X.size();i<nq;i++)
if((X[i]>>w)&1) _1.push_back(X[i]);
else _0.push_back(X[i]);
long long ans=0;
if(_1.size()&&_0.size()){
root=cnt=0,ans=(1<<30);
for(int i=0,n1=_1.size();i<n1;i++) addt(root,_1[i],30);
for(int i=0,n2=_0.size();i<n2;i++) ans=min(ans,ask(root,_0[i],30));
}
return ans+js(_1,w-1)+js(_0,w-1);
}
int main()
{
cin>>n;
for(int i=1,u,v,w;i<n;i++) cin>>u>>v>>w,adde(u+1,v+1,w),adde(v+1,u+1,w),X.push_back(0);
X.push_back(0),dfs(1,0),cout<<js(X,30);
}