[CSP-S模拟测试]:联盟(搜索+树的直径)
题目描述
$G$国周边的$n$个小国家构成一个联盟以抵御$G$国入侵,为互相支援,他们建立了$n−1$条双向通路,使得任意两个国家可以经过通路相互到达。
当一个国家受到攻击时,所有其它国家都会沿着最短路径前往这个国家进行支援,经过每条通路所需的时间均为$1$。定义一个国家的危险程度为所有国家全部赶到需要的最短时间,联盟的危险程度为所有国家的危险程度的最大值。
为了降低危险程度,联盟决定断开一条通路并任意连接一条通路,使得危险程度尽可能小,并要求改建完成之后任意两个国家可以经过通路互相到达。他们决定让你来设计方案,你需要告知在最优方案中可能断开哪些边,并给出任意一组最优方案。
输出格式
第一行一个正整数$n$。
接下来$n−1$行每行两个正整数,表示一条$u_i,v_i$之间的边。
输出格式
输出第一行一个整数表示最小危险程度。
第二行一个整数$k$,表示可能被断开的边的数量,接下来$k$个数,表示可能断开的边的编号,按升序输出。
接下来一行四个正整数表示一组最优方案,分别表示断开和新建的边的端点,只需给出任意一组合法的方案即可。
样例
样例输入:
4
1 2
2 3
3 4
样例输出:
2
2 1 3
3 4 4 2
数据范围与提示
对于$20\%$的数据,$n\leqslant 30$。
对于$40\%$的数据,$n\leqslant 300$。
对于$60\%$的数据,$n\leqslant 3,000$。
对于$100\%$的数据,$n\leqslant 300,000$。
如果你的答案仅第一行正确,你可以获得$25\%$的分数,
如果你的答案仅前两行正确,你可以获得$50\%$的分数,
为保证得到部分分请确保提交程序的输出格式符合题目要求。
题解
联盟的危险程度其实就是树的直径,这个我们使用两遍$DFS$即可解决。
然后我们还可以用两遍$DFS$求出每棵子树的直径。
现在我们枚举断边,至于如何连边,显然我们是要将两个联通块中直径的中点相连一定最优。
这时候我们已经知道第一问和第二问了。
第三问在跑$DFS$就解决了。
时间复杂度:$\Theta(n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[700000];
int head[300001],cnt=1;
int n;
int len,st,ed,ban;
int dis[2][300001];
int dfn[300001],low[300001];
int dp[2][300001];
int ans[300001],sum;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void dfs1(int x,int fa,int tim)
{
if(tim>=len)
{
len=tim;
st=x;
}
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa&&(ban!=i)&&((ban^1)!=i))dfs1(e[i].to,x,tim+1);
}
void dfs2(int x,int fa,int tim)
{
if(tim>=len)
{
len=tim;
ed=x;
}
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa&&(ban!=i)&&((ban^1)!=i))
{
dfs2(e[i].to,x,tim+1);
dis[1][i>>1]=e[i].to;
}
}
bool dfs3(int x,int fa)
{
dfn[++dfn[0]]=x;
if(x==ed)return 1;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa&&(ban!=i)&&((ban^1)!=i)&&dfs3(e[i].to,x))
{
low[i>>1]=1;
return 1;
}
dfn[0]--;
return 0;
}
int dfs4(int x,int fa)
{
int maxn=0;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa)
{
int flag=dfs4(e[i].to,x);
dp[0][x]=max(dp[0][x],dp[0][e[i].to]);
dp[0][x]=max(dp[0][x],flag+maxn);
maxn=max(maxn,flag);
}
return maxn+1;
}
int dfs5(int x,int fa)
{
int maxn=0;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa)
{
int flag=dfs5(e[i].to,x);
dp[1][x]=max(dp[1][x],dp[1][e[i].to]);
dp[1][x]=max(dp[1][x],flag+maxn);
maxn=max(maxn,flag);
}
return maxn+1;
}
int main()
{
ans[0]=1<<30;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);add(y,x);
}
dfs1(1,0,0);
len=0;
dfs2(st,0,0);
dfs3(st,0);
dfs4(st,0);
dfs5(ed,0);
for(int i=1;i<n;i++)
{
if(e[i<<1].to==dis[1][i])dis[0][i]=e[i<<1|1].to;
else dis[0][i]=e[i<<1].to;
}
for(int i=1;i<n;i++)
if(!low[i])
{
ans[i]=max((len+1)/2+min(dp[0][e[i<<1].to]+1,dp[0][e[i<<1|1].to]+1)/2+1,len);
ans[0]=min(ans[0],ans[i]);
}
else
{
ans[i]=max(max(dp[0][dis[1][i]],dp[1][dis[0][i]]),(dp[0][dis[1][i]]+1)/2+(dp[1][dis[0][i]]+1)/2+1);
ans[0]=min(ans[0],ans[i]);
}
printf("%d\n",ans[0]);
for(int i=1;i<n;i++)if(ans[i]==ans[0])sum++;
printf("%d ",sum);
for(int i=1;i<n;i++)if(ans[i]==ans[0])printf("%d ",i);
puts("");
for(int i=1;i<n;i++)
if(ans[i]==ans[0])
{
printf("%d %d ",e[i<<1].to,e[i<<1|1].to);
ban=i<<1;
len=dfn[0]=0;
dfs1(e[ban].to,0,0);
len=0;
dfs2(st,0,0);
dfs3(st,0);
printf("%d ",dfn[dfn[0]+1>>1]);
len=dfn[0]=0;
dfs1(e[ban^1].to,0,0);
len=0;
dfs2(st,0,0);
dfs3(st,0);
printf("%d ",dfn[dfn[0]+1>>1]);
break;
}
return 0;
}
rp++
[CSP-S模拟测试]:联盟(搜索+树的直径)的更多相关文章
- [CSP-S模拟测试]:Walk(树的直径+数学)
题目描述 给定一棵$n$个节点的树,每条边的长度为$1$,同时有一个权值$w$.定义一条路径的权值为路径上所有边的权值的最大公约数.现在对于任意$i\in [1,n]$,求树上所有长度为$i$的简单路 ...
- [10.12模拟赛] 老大 (二分/树的直径/树形dp)
[10.12模拟赛] 老大 题目描述 因为 OB 今年拿下 4 块金牌,学校赞助扩建劳模办公室为劳模办公室群,为了体现 OI 的特色,办公室群被设计成了树形(n 个点 n − 1 条边的无向连通图), ...
- [CSP-S模拟测试]:count(树分块)
题目描述 李华终于逃离了无尽的英语作文,重获自由的他对一棵树产生了兴趣.首先,他想知道一棵树是否能分成大小相同的几块(即切掉一些边,使得每个连通块的点数相同).然后,他觉得这个问题过于简单,于是他想知 ...
- [07/18NOIP模拟测试5]超级树
鬼能想到的dp定义:dp[i][j]表示在一棵i级超级树中,有j条路径同时存在且这j条路径没有公共点时,可能的情况数 刚开始我也没看懂,所以举个例子 如一个2级的超级树,父节点为1,左右儿子为2,3 ...
- [CSP-S模拟测试]:柱状图(树状数组+二分+三分)
题目描述 $WTH$获得了一个柱状图,这个柱状图一共有$N$个柱子,最开始第$i$根柱子的高度为$x_i$,他现在要将这个柱状图排成一个屋顶的形状,屋顶的定义如下:$1.$屋顶存在一个最高的柱子,假设 ...
- [CSP-S模拟测试]:影魔(树状数组+线段树合并)
题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...
- [7.18NOIP模拟测试5]砍树 题解(数论分块)
题面(加密) 又考没学的姿势……不带这么玩的…… 考场上打了个模拟 骗到30分滚粗了 稍加思考(滑稽)可将题面转化为: 求一个最大的$d$,使得 $\sum \limits _{i=1}^n {(\l ...
- [CSP-S模拟测试]:统计(树状数组+乱搞)
题目传送门(内部题120) 输入格式 第一行,两个正整数$n,m$. 第二行,$n$个正整数$a_1,a_2,...,a_n$,保证$1\leqslant a_i\leqslant n$,可能存在相同 ...
- 联赛模拟测试8 Dash Speed 线段树分治
题目描述 分析 对于测试点\(1\).\(2\),直接搜索即可 对于测试点\(3 \sim 6\),树退化成一条链,我们可以将其看成序列上的染色问题,用线段树维护颜色相同的最长序列 对于测试点\(7\ ...
随机推荐
- Visio 2016自定义模具与形状
Visio 2016自定义模具与形状 0. 什么是模具? 模具:一组形状的集合 1. 新建模具 打开Visio 2016,在空白的文件中选更多形状>>新建模具 2. 编辑模具 新建的模具已 ...
- HTML批量修改——正则表达式实践
目录 1.问题描述 2.初步研究 3.进一步研究 3.1提取2.*中的序号* 3.2提取标题 3.3选取全文 3.4替换 参考资料 1.问题描述 如下所示的一段HTML代码: ... <h2 a ...
- 诊断:MRP0: Background Media Recovery process shutdown with error ORA-19909
oracle12c data guard,从库无法应用日志,检查alert日至发现 2019-10-21T14:55:40.087819+08:00 MRP0: Background Media Re ...
- CSS的置换和非置换元素
一个来自面试的坑. 面试的时候考官先问了行内元素和块级元素的区别,这个不难理解.然后一脚就踩进了,置换元素的坑.例如img就是行内置换元素,这种行内元素是可以设置宽高的. 什么是置换元素 一个内容不受 ...
- [Bzoj1030][JSOI2007]文本生成器(AC自动机&dp)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1030 最最最常见的多串匹配问题!题目求至少包含一个子串的方案数,则可以转化成全部方案-不 ...
- Codeforces 1119C(思维)
题面 传送门 分析 这种题的重点是寻找不变量 我们发现如果改变4个角,则每一行和每一列的xor和不会改变(1^0=0^1) 所以只要算出异或和然后比较就可以 代码 #include<iostre ...
- linux上执行jmeter脚本
1.linux上安装jmeter 将windows上的zip包直接放到linux上 进入bin目录,chmod 777 jmeter 修改环境变量: 1 2 3 4 # vim /etc/profil ...
- 一个简单的winform程序调用webservices
本文原创,如需转载,请标明源地址,谢谢合作!http://blog.csdn.net/sue_1989/article/details/6597078 本文的编写IDE为VSTS2008和.NET F ...
- C#设计模式:桥接模式(Bridge Pattern)
一,桥接模式,直接上代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...
- vue-cli3脚手架的安装
如果之前有安装过其他的版本的话,要先卸载 卸载:npm uninstall vue-cli-g 或 yarn global remove vue-cli 安装:npm i @vue/cli -g ...