占领

题目描述

白云和白兔想占领一棵树。白云列举了游戏玩法:∙ 首先,白云任意选择一个结点𝑘,把这个结点占领,其它结点都未本占领。

每一轮,白云可以选择若干个已经被占领的点,然后分别从每个点出发,找一条出边,把到达的结点占领。∙

当所有结点都被占领时游戏结束。

白兔想知道,选择一个最优的𝑘,白云最少几轮可以完成游戏。

接下来白云和白兔想一起玩游戏,规则是这样:∙

一开始,白云选择了𝑎号点,白兔选择了𝑏号点,这两个结点都被占领,其它点都未被占领。∙

每一轮,白兔可以选择若干个已经被占领的点,然后分别从每个点出发,找任意一条出边,把到达的结点占领。∙

当所有结点都被占领时游戏结束。

白兔还想知道,最小多少轮可以占领所有结点?

注意,这个游戏的𝑎和𝑏是固定的。

输入

第一行三个数𝑛, 𝑎, 𝑏。

接下来𝑛 − 1行,每行两个数表示这棵树。

输出

输出两行。

第一行是第一个游戏的答案。

第二行是第二个游戏的答案。

样例输入

6 2 1
1 2
2 3
2 4
1 5
5 6
3

样例输出

3
2

样例解释

第一问:一开始选择点1。

第一轮,从1出发,占领2。

第二轮,从2出发,占领3,从1出发,占领5。

第三轮,从2出发,占领4,从5出发,占领6。

第二问:一开始1, 2两个点被占领。

第一轮,从1出发,占领5,从2出发,占领4。

第二轮,从5出发,占领6,从2出发,占领3。

数据范围

30% : 𝑛 ≤ 1000
2 ≤ 𝑛 ≤ 3 * 105
𝑎, 𝑏 ∈ [1, 𝑛], 𝑎 ̸= 𝑏

  


  • 首先要 dp+贪心+换根 求出第一问。

  • 先钦定一个点为根节点(第一个游戏的起始点),之后就有子树的概念。

  • 设 F【i】表示 i 这棵子树的答案。

  • 转移时,将一个节点的儿子的函数值从大到小排序,其 F 值即为 max{ F【sonk】+k };

  • 对于第二问,答案一定是将这棵树分为两个连通块。

  • 将 a 到 b 的路径提取出来。

  • 如果枚举断点的话,就可以拿到部分分了。

  • 发现点的贡献是单峰的,可以考虑三分。

  • 然而我的三分被卡了。

  • 然后又发现贡献值是取 max 的,于是可以二分。

  • 三分转化为二分。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int N=300050;
  4 int n,a,b,x,y,tot;
  5 int ans1,ans2;
  6 int head[N],sum;
  7 int nxt[N<<1];
  8 int ver[N<<1];
  9 int f[N],g[N];
 10 int pre[N],goal;
 11 int t[N],top;
 12 int tx[N],cnt;
 13 int ans[N];
 14 bool cmp(int x,int y)
 15 {
 16     return f[x]>f[y];
 17 }
 18 void add(int x,int y)
 19 {
 20     nxt[++tot]=head[x];
 21     head[x]=tot;
 22     ver[tot]=y;
 23 }
 24 void dfs1(int u,int fa)
 25 {
 26     for(int i=head[u];i;i=nxt[i])
 27         if(ver[i]!=fa&&ver[i]!=goal)
 28             dfs1(ver[i],u);
 29     top=0;    f[u]=1;
 30     for(int i=head[u];i;i=nxt[i])
 31         if(ver[i]!=fa&&ver[i]!=goal)
 32             t[++top]=ver[i];
 33     sort(t+1,t+top+1,cmp);
 34     for(int i=1;i<=top;++i)
 35         f[u]=max(f[u],f[t[i]]+i);
 36 }
 37 void dfs2(int u,int fa)
 38 {
 39     f[fa]=g[u];    t[top=1]=fa;
 40     for(int i=head[u];i;i=nxt[i])
 41         if(ver[i]!=fa)
 42             t[++top]=ver[i];
 43     sort(t+1,t+top+1,cmp);
 44     for(int i=1;i<=top;++i)
 45         pre[i]=max(pre[i-1],f[t[i]]+i);
 46     ans1=min(ans1,pre[top]);
 47     int tmp=0;
 48     for(int i=top;i>=1;--i)
 49     {
 50         g[t[i]]=max(tmp,pre[i-1]);
 51         tmp=max(tmp,f[t[i]]+i-1);
 52     }
 53     for(int i=head[u];i;i=nxt[i])
 54         if(ver[i]!=fa)
 55             dfs2(ver[i],u);
 56 }
 57 void dfs(int u,int fa)
 58 {
 59     tx[++cnt]=u;if(u==b)    return ;
 60     for(int i=head[u];i;i=nxt[i])
 61         if(ver[i]!=fa)
 62         {
 63             dfs(ver[i],u);
 64             if(tx[cnt]==b)
 65                 return ;
 66         }
 67     --cnt;
 68 }
 69 int calc(int u)
 70 {
 71     if(ans[u])    return ans[u];
 72     goal=tx[u+1];    dfs1(a,0);
 73     goal=tx[u];        dfs1(b,0);
 74     ans[u]=max(f[a],f[b]);
 75     ans2=min(ans2,ans[u]);
 76     return ans[u];
 77 }
 78 int main()
 79 {
 80     scanf("%d%d%d",&n,&a,&b);
 81     ans1=ans2=n;
 82     for(int i=1;i<n;++i)
 83     {
 84         scanf("%d%d",&x,&y);
 85         add(x,y);    add(y,x);
 86     }
 87     dfs(a,0);
 88     dfs1(1,0);
 89     dfs2(1,0);
 90     calc(1);
 91     int l=1,r=cnt-1;
 92     while(l<r)
 93     {
 94         int mid=(l+r)>>1;
 95         calc(mid);
 96         if(f[a]>f[b])    r=mid;
 97         else    l=mid+1;
 98     }
 99     printf("%d\n%d",ans1-1,ans2-1);
100     return 0;
101 }
View Code

 

posted @ 2019-02-15 17:06  Hevix  阅读(322)  评论(0编辑  收藏  举报