Achen毒瘤模擬賽T2——毒瘤最優化
阿新 • • 發佈:2018-09-29
fine ret turn 優化 樹的重心 ace set etc node
題目大意:給出一棵樹,樹的生成圖G上任意兩點相連且兩點的距離為樹上兩點的帶權距離,求圖上最短的哈密頓回路。
坑點:如果一直想從哈密頓回路入手,那你就要GG了,像我一樣想出一個錯解DP。
然而,只需畫幾個圖,你就會大致猜出一個方法:以樹的重心為根,把書分為若幹部分且每個部分大小不超過n/2,那麽必定有一種方法使得lca全部取得根,所以對於一條邊(u,pre[u]),他會被經過2*s[u]次。
然後就可以依次計算最小值了(?????為什麽?????)
這裏有一個引理:有n個不同顏色的小球,若出現次數最多的顏色的小球能被分隔開,則一定存在一種排列方式使任意相鄰小球不同色。證明很簡單,由於出現次數最多的小球能被隔開,按BFS方式每次取出一種顏色的球,這樣一定會剩下出現次數最多的球,再把這些球插進序列中就好。由於保證了出現次數最多的顏色的小球能被分隔開,所以這個操作一定能成功
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<queue> #include<ctime> #define MAXN 200005 #define ll long long #define maxn 15 #define maxs 1000005 #define inf 1e9 #define eps 1e-9 using namespacestd; inline char gc() { static char now[1<<16],*S,*T; if (T==S) { T=(S=now)+fread(now,1,1<<16,stdin); if (T==S) return EOF; } return *S++; } inline ll readlong() { ll x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘)f=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x*=10; x+=ch-‘0‘; ch=getchar(); } return x*f; } inline int read() { int x=0,f=1; char ch=getchar(); while(ch<‘0‘||ch>‘9‘) { if(ch==‘-‘)f=-1; ch=getchar(); } while(ch>=‘0‘&&ch<=‘9‘) { x*=10; x+=ch-‘0‘; ch=getchar(); } return x*f; } void putint(long long t) { int ans[40]= {0}; for(; t; t/=10)ans[++ans[0]]=t%10; for(; ans[0]; ans[0]--)putchar(‘0‘+ans[ans[0]]); putchar(‘\n‘); } const int N=1000005; struct node{ int to,nxt; }e[N<<1]; int h[N],cnt; void add(int x,int y){ e[++cnt]=(node){y,h[x]}; h[x]=cnt; e[++cnt]=(node){x,h[y]}; h[y]=cnt; } int sum[N],ans[N]; int tot; int n; void dfs(int x,int fa){ sum[x]=1; for(int i=h[x];i;i=e[i].nxt){ int y=e[i].to; if(y==fa){ continue; } dfs(y,x); sum[x]+=sum[y]; } if(fa){ ans[++tot]=2*min(sum[x],n-sum[x]); } } int main(){ n=read(); for(int i=1;i<n;i++){ int x=read(); int y=read(); add(x,y); } dfs(1,0); sort(ans+1,ans+tot+1); ll A=0; for(int i=1;i<=tot;i++){ A=(A+1ll*i*ans[tot-i+1]); } printf("%lld\n",A); return 0; }
Achen毒瘤模擬賽T2——毒瘤最優化