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; }
寻找真正的热爱