占领
题目描述
白云和白兔想占领一棵树。白云列举了游戏玩法:∙ 首先,白云任意选择一个结点𝑘,把这个结点占领,其它结点都未本占领。
每一轮,白云可以选择若干个已经被占领的点,然后分别从每个点出发,找一条出边,把到达的结点占领。∙
当所有结点都被占领时游戏结束。
白兔想知道,选择一个最优的𝑘,白云最少几轮可以完成游戏。
接下来白云和白兔想一起玩游戏,规则是这样:∙
一开始,白云选择了𝑎号点,白兔选择了𝑏号点,这两个结点都被占领,其它点都未被占领。∙
每一轮,白兔可以选择若干个已经被占领的点,然后分别从每个点出发,找任意一条出边,把到达的结点占领。∙
当所有结点都被占领时游戏结束。
白兔还想知道,最小多少轮可以占领所有结点?
注意,这个游戏的𝑎和𝑏是固定的。
输入
第一行三个数𝑛, 𝑎, 𝑏。
接下来𝑛 − 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 的,于是可以二分。
• 三分转化为二分。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }