判斷素數
阿新 • • 發佈:2020-07-25
題目描述:
Mr. W got a new graph with N vertices and N - 1 edges. It's a connected graph without cycles. Each edge should have an ugly value. To make the graph more beautiful, Mr. W hope you can help him modify it. You can delete or add one edge with an ugly value at a time and you can do it as many times as you want. But the following conditions should be satisfied at any time:輸入描述:
輸出描述:
示例:
輸入 6 0 1 1 1 2 4 1 3 3 0 4 5 0 5 2
輸出 7
做法:我們腦袋一拍,可以發現任意兩個點之間連邊的權值都是固定的。
由於可以得出:圖始終聯通,所以兩點間始終存在至少一條路徑,如果存在多條,那麼根據:
- 環的異或和為0;
- 兩點間的路徑的異或和應該相等,且始終是固定的。
所以可以給每個點一個權值,那麼兩點間的連邊權值就應該是兩端點權的異或。
接下來的問題就是異或最小生成樹。
字典樹 就TM煩。
接下來便是參考程式碼:
#include<bits/stdc++.h> using namespace std; int n,tot,cnt; int head[100005],dp[100005],tree[30000010][2]; long long ans; struct node { int v; int w; int next; }a[100005<<1]; void dfs(intView Codex,int h) { for (int i=head[x]; i!=-1; i=a[i].next) { int v=a[i].v; if(v==h) continue; dp[v]=dp[x]^a[i].w; dfs(v,x); } } void insert(int x) { int p=0; for (int i=29; i>=0; i--) { int now=x>>i&1; if(!tree[p][now]) { cnt++; tree[p][now]=cnt; tree[cnt][0]=0; tree[cnt][1]=0; } p=tree[p][now]; } } int ask(int x) { int p=0,ans=0; for (int i=29; i>=0; i--) { int now=x>>i&1; if(!tree[p][now]) now^=1; p=tree[p][now]; if(now) ans+=1<<i; } return ans; } void bfs(int x, int l, int r) { if(x<0) return ; int mid=l-1; for (int i=l; i<=r; i++) if(!(1<<x&dp[i])) mid=i; if(l<=mid) bfs(x-1,l,mid); if(mid<r) bfs(x-1,mid+1,r); if(mid<l || mid>=r) return ; cnt=0; tree[0][0]=0; tree[0][1]=0; for (int i=l; i<=mid; i++) insert(dp[i]); int minn=0x3f3f3f3f; for (int i=mid+1; i<=r; i++) minn=min(minn,dp[i]^ask(dp[i])); ans+=minn; } int main() { memset(head,-1,sizeof(head)); scanf("%d",&n); int x,y,z; for (int i=1,u,v,w; i<n; i++){ scanf("%d%d%d",&x,&y,&z); x++,y++; a[tot].v=y; a[tot].w=z; a[tot].next=head[x]; head[x]=tot++; a[tot].v=x; a[tot].w=z; a[tot].next=head[y]; head[y]=tot++; } dfs(1,0); sort(dp+1,dp+1+n); bfs(29,1,n); printf("%lld\n", ans); return 0; }//碼農教程請不要爬我程式碼