• [atARC088F]Christmas Tree


    合并具有交换律,因此即将一个连通块(初始为空)与一条链合并(其中各选1点,初始直接替换)

    把插入改为染色,等价于对树上的一条链(包括点和边)染色,其中恰好有1个已经被染色的点(初始任意)

    对于”恰有1个已被染色的点“这个条件,其实是可以忽略的,证明如下:

    由于染色的点必然是一个完整的连通块,即如果包含两个被染色的点,这两个点之间的路径也已经被染色,完全可以在第一次添加时延长下去

    对于存在被染色的点,只需要找到一个已经被染色的点(仍有出边未被染色),先操作经过其的操作即可

    由此,题目即变为通过$A$次染长度不超过$B$的链,使得所有点和边(其实仅需要考虑边)都被染色

    先考虑最小的$A$,若有$s$个奇数度数的点,则$Age frac{s}{2}$(显然$s$为偶数),这是因为每一条链至多改变两个点度数的奇偶性,而初始都为偶数,因此至少$frac{s}{2}$条链

    同时,每一次选择两个奇数度数的点连结,类似重心的构造方法也可以得到一组合法方案

    最小的$B$同noip2018D1T3,总时间复杂度为$o(nlog^{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 }
    View Code
  • 相关阅读:
    python学习笔记之---面向对象的三大特性
    python学习笔记之---类的属性和方法的访问总结
    python学习笔记之--类的三种方法
    python学习笔记之--面向对象技术
    python学习笔记之--面向对象和面向过程
    整数反转
    逻辑运算&map函数&filter函数&reduce函数
    python整理&&集合学习
    python基本数据类型
    python基础&条件语句
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14131468.html
Copyright © 2020-2023  润新知