1. 程式人生 > >【EOJ3654】管理孩子(貪心,二分答案)

【EOJ3654】管理孩子(貪心,二分答案)

題意:有一棵n個點的樹,其中有k個是關鍵點,將樹分割成若干部分,每部分至少包含一個關鍵點,求最大分割大小的最小值

思路:

最後特判一下f[1]的值

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<string>
  4 #include<cmath>
  5 #include<iostream>
  6 #include<algorithm>
  7 #include<map>
  8 #include<queue>
  9
#include<vector> 10 #include<ctime> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned int uint; 14 typedef unsigned long long ull; 15 typedef pair<int,int> PII; 16 typedef vector<int> VI; 17 #define fi first 18 #define se second 19 #define MP make_pair 20
#define mem0(a) memset(a,0,sizeof(a)) 21 #define N 210000 22 #define M 130 23 #define MOD 1000000007 24 #define eps 1e-8 25 #define pi acos(-1) 26 #define oo 1000000000 27 28 int flag[N],f[N],a[N],n,mx; 29 vector<int>c[N]; 30 31 void dfs(int u) 32 { 33 flag[u]=1; 34 if(a[u]) 35 { 36 int
t=0; 37 for(int i=0;i<=(int)c[u].size()-1;i++) 38 { 39 int v=c[u][i]; 40 if(!flag[v]) 41 { 42 dfs(v); 43 if(f[v]<0) t-=f[v]; 44 } 45 } 46 f[u]=t+1; 47 } 48 else 49 { 50 int t=0,s=oo; 51 for(int i=0;i<=(int)c[u].size()-1;i++) 52 { 53 int v=c[u][i]; 54 if(!flag[v]) 55 { 56 dfs(v); 57 if(f[v]<0) t-=f[v]; 58 else s=min(s,f[v]); 59 } 60 } 61 if(mx-s>=t+1) f[u]=s+t+1; 62 else f[u]=-t-1; 63 } 64 } 65 66 int isok(int m) 67 { 68 mem0(flag); 69 mem0(f); 70 mx=m; 71 dfs(1); 72 int flag=1; 73 if(f[1]<0) return 0; 74 for(int i=1;i<=n;i++) 75 if(abs(f[i])>m) return 0; 76 return 1; 77 } 78 79 int main() 80 { 81 int k; 82 scanf("%d%d",&n,&k); 83 for(int i=1;i<=n-1;i++) 84 { 85 int x,y; 86 scanf("%d%d",&x,&y); 87 c[x].push_back(y); 88 c[y].push_back(x); 89 } 90 for(int i=1;i<=k;i++) 91 { 92 int x; 93 scanf("%d",&x); 94 a[x]=1; 95 } 96 int l=1,r=n,last=n; 97 while(l<=r) 98 { 99 int mid=(l+r)>>1; 100 if(isok(mid)){last=mid; r=mid-1;} 101 else l=mid+1; 102 } 103 printf("%d\n",last); 104 return 0; 105 }