zoukankan      html  css  js  c++  java
  • 解题:POI 2004 String

    题面

    首先我们要有一个明确的构造思路

    对于非根节点,我们把子树连上来的线两两配对,这样如果它有奇数个子树就会剩一个,这时候把这根线传给父亲即可。对于根节点还是两两配对,但是注意如果它也有奇数个子树就不能剩了,必须把这根线算上。这样第一问的答案就是每个非根节点贡献度数除以二下取整,根节点贡献度数除以二上取整

    第二问我们先二分答案,仍然沿用这个思路,这时我们要让最长的最短,于是我们每次把子树里传上来的线塞进一个multiset。讨论:对于有奇数个子树的情况,从大到小枚举线,二分出和当前的线拼起来不超过二分的$mid$的最长的线,然后把它们删掉,最后剩下的那根传给父亲。注意如果有一根线找不到配对也不一定失败,我们先视为把它传给父亲,然后看看剩下的还能不能拼好。对于有偶数个子树的情况,我们直接塞一个零进multiset里去,然后按奇数的方法做,这是等价的。对于根节点,我们去除掉塞零和留线这两个操作判定即可。

     1 #include<set>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 const int N=10005;
     7 int p[N],noww[2*N],goal[2*N],deg[N],dp[N];
     8 int n,t1,t2,cnt,mins,l,r,mid,ans;
     9 multiset<int> se;
    10 multiset<int>::iterator it;
    11 void link(int f,int t)
    12 {
    13     noww[++cnt]=p[f];
    14     goal[cnt]=t,p[f]=cnt;
    15 }
    16 bool check(int nde,int fth)
    17 {
    18     if(deg[nde]==1&&nde!=1) 
    19         {dp[nde]=0; return true;}
    20     for(int i=p[nde];i;i=noww[i])
    21         if(goal[i]!=fth&&!check(goal[i],nde))
    22             return false;
    23     se.clear();
    24     for(int i=p[nde];i;i=noww[i])
    25         if(goal[i]!=fth)
    26             se.insert(dp[goal[i]]+1); 
    27     if(nde==1)
    28     {
    29         while(se.size()>1)
    30         {
    31             long long mem=*(--se.end());
    32             se.erase(--se.end()); it=se.upper_bound(mid-mem); 
    33             if(it!=se.begin()) it--; else return false;
    34             if((*it)+mem>mid) return false; se.erase(it);
    35         }
    36         if(se.size()) return (*se.begin())<=mid;
    37         else return true;
    38     }
    39     else
    40     {
    41         int must=0;
    42         if(se.size()%2==0) se.insert(0);
    43         while(se.size()>1)
    44         {
    45             long long mem=*(--se.end()); 
    46             se.erase(--se.end()); it=se.upper_bound(mid-mem); 
    47             if(it!=se.begin()) it--; else return false; 
    48             if((*it)+mem>mid) 
    49             {
    50                 if(must) return false;
    51                 else
    52                 {
    53                     must=*(--se.end());
    54                     continue;
    55                 }
    56             }
    57             else se.erase(it);
    58         }
    59         return (dp[nde]=must?must:(*se.begin()))<=mid;
    60     }
    61     return true;
    62 }
    63 int main ()
    64 {
    65     scanf("%d",&n);
    66     for(int i=1;i<n;i++)
    67     {
    68         scanf("%d%d",&t1,&t2);
    69         link(t1,t2),link(t2,t1);
    70         deg[t1]++,deg[t2]++;
    71     }
    72     mins+=(deg[1]+1)/2;
    73     for(int i=2;i<=n;i++)
    74         mins+=(deg[i]-1)/2;
    75     l=1,r=n;
    76     while(l<=r)
    77     {
    78         mid=(l+r)/2;
    79         if(check(1,0)) r=mid-1,ans=mid;
    80         else l=mid+1;
    81     }
    82     printf("%d %d",mins,ans);
    83     return 0;
    84 }
    View Code
  • 相关阅读:
    Spring Boot 2.x实战之StateMachine
    Spring Boot实战之定制type Formatters
    Spring Boot实战之定制URL匹配规则
    Spring Boot项目中如何定制servlet-filters
    Mac高效开发之iTerm2、Prezto和Solarized主题
    Spring Boot应用的健康监控
    Spring Boot构建的Web项目如何在服务端校验表单输入
    Spring Boot项目中如何定制PropertyEditors
    Spring Boot项目中如何定制拦截器
    在Spring Boot项目中使用Spock测试框架
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9809409.html
Copyright © 2011-2022 走看看