[atARC088F]Christmas Tree
合并具有交换律,因此即将一个连通块(初始为空)与一条链合并(其中各选1点,初始直接替换)
把插入改为染色,等价于对树上的一条链(包括点和边)染色,其中恰好有1个已经被染色的点(初始任意)
对于”恰有1个已被染色的点“这个条件,其实是可以忽略的,证明如下:
由于染色的点必然是一个完整的连通块,即如果包含两个被染色的点,这两个点之间的路径也已经被染色,完全可以在第一次添加时延长下去
对于存在被染色的点,只需要找到一个已经被染色的点(仍有出边未被染色),先操作经过其的操作即可
由此,题目即变为通过$A$次染长度不超过$B$的链,使得所有点和边(其实仅需要考虑边)都被染色
先考虑最小的$A$,若有$s$个奇数度数的点,则$A\ge \frac{s}{2}$(显然$s$为偶数),这是因为每一条链至多改变两个点度数的奇偶性,而初始都为偶数,因此至少$\frac{s}{2}$条链
同时,每一次选择两个奇数度数的点连结,类似重心的构造方法也可以得到一组合法方案
最小的$B$同noip2018D1T3,总时间复杂度为$o(n\log^{2}n)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 struct ji{ 5 int nex,to; 6 }edge[N<<1]; 7 vector<int>v; 8 int E,n,x,y,sum,ans,head[N],r[N],g[N],f[N]; 9 void add(int x,int y){ 10 edge[E].nex=head[x]; 11 edge[E].to=y; 12 head[x]=E++; 13 } 14 int calc(int k){ 15 int s=0; 16 for(int i=v.size()-1,j=0;i>=j;i--){ 17 if (i==k)i--; 18 if (j==k)j++; 19 if (i>=j){ 20 s++; 21 if (v[i]+v[j]<=ans)j++; 22 } 23 } 24 return s; 25 } 26 void dfs(int k,int fa){ 27 for(int i=head[k];i!=-1;i=edge[i].nex) 28 if (edge[i].to!=fa){ 29 dfs(edge[i].to,k); 30 f[k]+=f[edge[i].to]; 31 } 32 v.clear(); 33 for(int i=head[k];i!=-1;i=edge[i].nex) 34 if (edge[i].to!=fa){ 35 if (g[edge[i].to]+1==ans)f[k]++; 36 else v.push_back(g[edge[i].to]+1); 37 } 38 if (!v.size())return; 39 sort(v.begin(),v.end()); 40 int l=-1,r=v.size()-1,s=calc(r); 41 while (l<r){ 42 int mid=(l+r>>1); 43 if (calc(mid)==s)r=mid; 44 else l=mid+1; 45 } 46 f[k]+=s; 47 if (l<0)g[k]=0; 48 else g[k]=v[l]; 49 } 50 bool pd(int k){ 51 ans=k; 52 memset(f,0,sizeof(f)); 53 memset(g,0,sizeof(g)); 54 dfs(1,0); 55 return (f[1]+(g[1]>0)<=sum/2); 56 } 57 int main(){ 58 scanf("%d",&n); 59 memset(head,-1,sizeof(head)); 60 for(int i=1;i<n;i++){ 61 scanf("%d%d",&x,&y); 62 add(x,y); 63 add(y,x); 64 r[x]^=1; 65 r[y]^=1; 66 } 67 for(int i=1;i<=n;i++) 68 if (r[i])sum++; 69 printf("%d ",sum/2); 70 int l=1,r=n; 71 while (l<r){ 72 int mid=(l+r>>1); 73 if (pd(mid))r=mid; 74 else l=mid+1; 75 } 76 printf("%d",l); 77 }