[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\ ...
随机推荐
- Vagrant 手册之 Vagrantfile - 机器设置 config.vm
原文地址 配置的命名空间:config.vm config.vm 中的设置修改 Vagrant 管理的机器的配置. 1. 可用的设置项 config.vm.boot_timeout Vagrant 等 ...
- Learn Python the hard way, ex40 字典,可爱的字典
#!/usr/bin/python #coding:utf-8 cities ={'CA':'sf','MI':'dt','FL':'je'} #创建字典 cities['NY']='ny' #增加新 ...
- 【ABAP系列】SAP ABAP 给初学者-解读function函数的export和import等参数
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 给初学者-解读 ...
- _exit和exit的区别
在linux的标准库函数中,有一套称作高级I/O的函数,我们熟知的printf .fopen .fread .fwrite都在此列,他们也被称作缓冲I/O.其特征是对应每一个打开的文件,都存在一个缓冲 ...
- 爬虫(十一)—— 请求库(三)pypeteer请求库
曾经使用模拟浏览器操作(selenium + webdriver)来写爬虫,但是稍微有点反爬的网站都会对selenium和webdriver进行识别,网站只需要在前端js添加一下判断脚本,很容易就可以 ...
- oracle--用户区别sys和system
1.数据库的启动需要以SYSDBA/SYSOPER身份登录. 2.如果在同一主机上使用IPC连接到数据库使用操作系统授权,登录任何一个用户都可以拥有as sysdba和as sysoper. 3.sy ...
- httpclient模拟服务器请求
// 创建默认的httpClient实例. CloseableHttpClient httpclient = HttpClients.createDefault(); // 创建httppost Ht ...
- org.apache.hadoop.hive.ql.exec.DDLTask. MetaException错误问题
下载 http://www.java2s.com/Code/Jar/m/Downloadmysqlconnectorjavacommercial517binjar.htm 放到lib目录下,删除原本的 ...
- Codeforces 1114B (贪心)
题面 传送门 分析 答案很好看出,显然是选最大的m*k个数 那么如何构造方案呢 我们把最大的m*k个数的位置标记为1,其他标记为0 从左到右维护一个ptr,记录有标记的数的个数,如果当前有m个有标记的 ...
- Vue打包后访问静态资源路径问题
Vue介绍中static文件夹里放的是静态资源目录,如图片.字体等. 我们发现运行npm run start后本地图片路径是没问题的,但是打包上传后会怎么样呢? 我们知道,执行npm run buil ...