2020牛客暑期多校训练营(第五场) Graph
本题和cf 888G是一样的
利用分治算法
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 2e5+11;
typedef long long ll;
ll list[maxn];
ll tree[maxn*33][3];
int cnt=0;
ll add(ll x){//把数值插入字典树
int root = 0;
for(int i=29;i>=0;i--){
int t = (x>>i)&1;
if(!tree[root][t]) tree[root][t] = ++cnt;
root = tree[root][t];//向下爬
}
return 0;
}
ll find(ll x){//查找字典树里面和x异或最小的数值
int root = 0;
ll an =0 ;
for(int i= 29;i>=0;i--){
ll t = (x>>i)&1;
if(tree[root][t]) root = tree[root][t];
else{
root = tree[root][t^1];
an |= (1<<i);
}
}
return an;
}
ll ans = 0;
int dfs(int l,int r,int dep){
if(dep==-1||l>=r) return 0;
int mid = -100;
for(int i = l;i<=r;i++){
if((list[i]>>dep)&1) break;
mid = i;
}
if(mid == -100 || mid == r){//全是1
dfs(l,r,dep-1);
}
else{
dfs(l,mid,dep-1);
dfs(mid+1,r,dep-1);
}
if(mid==-100||mid==r) return 0;//dep位置全是0 或者全是1
for(int i = l;i<=mid;i++){
add(list[i]);
}
long long cns = 1e15;
for(int i = mid+1;i<=r;i++){
long long a = find(list[i]);
cns = min(cns,a);
}
ans += 1LL*cns;
for(int i=0;i<=cnt;i++){
tree[i][0] = tree[i][1] = 0;
}
cnt = 0;
return 0;
}
struct Node{
int p;
int len;
Node(int aa,int bb):p(aa),len(bb){}
};
vector<Node>G[maxn];
void add(int x,int y,int len){
G[x].push_back(Node(y,len));
}
int dfs2(int x,int fa,int dep){
list[x] = dep;
for(int i=0;i<G[x].size();i++){
int p = G[x][i].p;
int ln = G[x][i].len;
if(p == fa) continue;
dfs2(p,x,(dep^ln));
}
return 0;
}
int main(){
ios::sync_with_stdio(false);
int n;
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y,len;
scanf("%d%d%d",&x,&y,&len);
x++;
y++;
add(x,y,len);
add(y,x,len);
}
dfs2(1,-1,0);
sort(list+1,list+1+n);
ans = 0;
dfs(1,n,29);
printf("%lld\n",ans);
return 0;
}
寻找真正的热爱

浙公网安备 33010602011771号