[IOI2013]Dreaming
一道非常类似的题目(link)
试题大意
给你一棵含有$n$个节点的有边权森林,问每次连边将会用$L$的代价,问你若此图通过加边成为树时的最小直径。$n \leq 5\times 10^5$
试题分析
我们可以发现若两棵树要是在合并连接的点一定与树的中心有关。树的中心指对于当$i$为根时,子树上权值和最大的最小。
为什么,应为树的直径的情况只有单独一棵树,两棵树和在一起的,且那时要是合并就是的是树的中心。但其实$CF$那题应该求树的中心也行,因为那是边权都会为$1$.
所以会发现其实应该如果说要把树建完以后会发现是一个菊花树,且根为权重最大的联通块的根。因为若是小的当根的话那么就会多算了一颗树,所以最多只需要算两颗即可。
所以说我们每次处理好中心到叶子节点的最大距离是多少,然后就可以直接去计算答案了。
并且为什么最多只要算到联通块个数$\leq 3$呢,因为刚才说了这是一颗菊花图,所以我们最多有用的其实是两颗子树。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int N=;
struct node{
int u,v,w,nex;
}x[N<<];
int cnt,head[N],n,m,l;
void add(int u,int v,int w){
x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
}
int dp[N][],dis[N],col,vis[N],son[N];
/*0最长 1 次长*/
void dfs1(int f,int fath){
vis[f]=;
for(int i=head[f];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
dfs1(x[i].v,f);
if(dp[x[i].v][]+x[i].w>=dp[f][]){dp[f][]=dp[f][];dp[f][]=dp[x[i].v][]+x[i].w,son[f]=x[i].v;}
else if(dp[x[i].v][]+x[i].w>dp[f][]){dp[f][]=dp[x[i].v][]+x[i].w;}
}
return;
}
int ans,k;
void dfs2(int f,int fath,int Dis){
if(Dis>dp[f][]){
dp[f][]=dp[f][];dp[f][]=Dis;son[f]=fath;
}
else if(Dis>dp[f][]){dp[f][]=Dis;}
ans=max(ans,dp[f][]);k=min(k,dp[f][]);
for(int i=head[f];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
if(son[f]==x[i].v) dfs2(x[i].v,f,dp[f][]+x[i].w);
else dfs2(x[i].v,f,dp[f][]+x[i].w);
}
}
int calc[N];
signed main(){
memset(head,-,sizeof(head));
n=read(),m=read(),l=read();
for(int i=;i<=m;i++){
int u=read()+,v=read()+,w=read();
add(u,v,w),add(v,u,w);
}
for(int i=;i<=n;i++){
if(!vis[i]){
dfs1(i,);
k=INT_MAX;
dfs2(i,,);
calc[++col]=k;
}
}
sort(calc+,calc+col+);
if(col>=) ans=max(ans,calc[col]+calc[col-]+l);
if(col>=) ans=max(ans,calc[col-]+calc[col-]+*l);
printf("%d",ans);
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
using namespace std;
inline int read(){
int f=,ans=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
const int N=;
struct node{
int u,v,w,nex;
}x[N<<];
int cnt,head[N],n,m,l;
void add(int u,int v,int w){
x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
}
int dp[N][],dis[N],col,vis[N],son[N];
/*0最长 1 次长*/
void dfs1(int f,int fath){
vis[f]=;
for(int i=head[f];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
dfs1(x[i].v,f);
if(dp[x[i].v][]+x[i].w>=dp[f][]){dp[f][]=dp[f][];dp[f][]=dp[x[i].v][]+x[i].w,son[f]=x[i].v;}
else if(dp[x[i].v][]+x[i].w>dp[f][]){dp[f][]=dp[x[i].v][]+x[i].w;}
}
return;
}
int ans,k,pos;
struct Node{
int pos,calc;
}S[N<<];
void dfs2(int f,int fath,int Dis){
if(Dis>dp[f][]){
dp[f][]=dp[f][];dp[f][]=Dis;son[f]=fath;
}
else if(Dis>dp[f][]){dp[f][]=Dis;}
ans=max(ans,dp[f][]);k=min(k,dp[f][]);
if(dp[f][]==k) pos=f;
for(int i=head[f];i!=-;i=x[i].nex){
if(x[i].v==fath) continue;
if(son[f]==x[i].v) dfs2(x[i].v,f,dp[f][]+x[i].w);
else dfs2(x[i].v,f,dp[f][]+x[i].w);
}
}
bool cmp(Node x1,Node x2){return x1.calc<x2.calc;}
signed main(){
memset(head,-,sizeof(head));
n=read(),m=read(),l=;
for(int i=;i<=m;i++){
int u=read(),v=read(),w=;
add(u,v,w),add(v,u,w);
}
for(int i=;i<=n;i++){
if(!vis[i]){
dfs1(i,);
k=INT_MAX;
dfs2(i,,);
S[++col].calc=k;
S[col].pos=pos;
}
}
sort(S+,S+col+,cmp);
if(col>=) ans=max(ans,S[col].calc+S[col-].calc+l);
if(col>=) ans=max(ans,S[col-].calc+S[col-].calc+*l);
printf("%d\n",ans);
for(int i=col-;i>=;i--) cout<<S[col].pos<<" "<<S[i].pos<<endl;
}
CF
[IOI2013]Dreaming的更多相关文章
- bzoj 3246 [Ioi2013]Dreaming 贪心
[Ioi2013]Dreaming Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 638 Solved: 241[Submit][Status][Di ...
- 【bzoj3246】 Ioi2013—Dreaming
www.lydsy.com/JudgeOnline/problem.php?id=3246 (题目链接) 题意 给出一棵不完全的树,要求在树上连最少的边使得所有点联通,并且使得两点间最大距离最小. S ...
- BZOJ3246 [Ioi2013]Dreaming
Description Serpent(水 蛇)生活的地方有N个水坑,编号为0,...,N - 1,有M条双向小路连接这些水坑.每两个水坑之间至多有一条路径(路径包含一条或多条小路)相互连接,有些水坑 ...
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- 【IOI2013】【Bzoj3246】Dreaming
http://www.lydsy.com/JudgeOnline/problem.php?id=3246 中文题面 天地之初,世界尚在遥远的梦想之中. Serpent(水蛇)生活的地方有N个水坑,编号 ...
- 读书笔记:《梦断代码Dreaming in Code》
读书笔记:<梦断代码Dreaming in Code> 拿到<梦断代码>书后,一口气翻了一遍,然后又用了3天时间仔细读了一遍,也不禁掩卷长叹一声,做软件难.虽难,仍要继续走下去 ...
- BZOJ3249 : [ioi2013]game
线段树套Treap 外层的线段树需要动态开节点 内层Treap需要注意的是,相同y坐标的点不一定是同一个点,所以需要再次离散 空间$O(n\log n)$ 时间$O(n\log^2n)$ #inclu ...
- 《梦断代码Dreaming In Code》阅读笔记(三)
最后这几章感觉上更多是从软件完成整体上来讲的.比如说技术.方法等. 在我看来,其实一个团队一直坚持一种好的.先进的方法是不可少的.如果一个优秀的团队刚愎自用,只随着成员们喜好发展,那不能长久.比如说, ...
- 《梦断代码Dreaming In Code》阅读笔记(二)
这段时间一口气读了5章,所以想着现在一块写阅读笔记. 在阅读的这段时间,我一直是晚上进行阅读,很多时候都是读完一看已经一个小时了,效果还不错.闲话不表,说说阅读心得. 关于底层语言或是低级语言,我之前 ...
随机推荐
- Docker--从安装到搭建环境
docker 1. ubuntu下安装docker 安装docker有两种方法: 一种是用官方的bash脚本一键安装. 直接一条命令就解决了: $ curl -sSL https://get.dock ...
- Nginx之一:Nginx的编译安装
一.Nginx简介 官方网址:http://nginx.org/ Nginx是由1994年毕业于俄罗斯国立莫斯科鲍曼科技大学的同学为俄罗斯rambler.ru公司开发的,开发工作最早从2002年开始, ...
- linux计划任务 学习笔记
原文链接: http://www.tsingfeng.com/?tag=cronjob 本文说的计划任务是指linux的Cronjob.语法 下面是个简单的计划任务: 10 * * * * /usr/ ...
- 基于spec探路者团队贪吃蛇作品的评论
1 运动功能 由以上两图贪吃蛇的位置不同可知,运动功能实现.并且我能够通过使用键盘上的上下左右方位键控制蛇的移动方向,蛇在控制的方向上进行直线前进. 2 吃食物功能 以上两图可知吃食物功能实现.当界面 ...
- c# 消息机制
1.windows系统是一个消息驱动的系统,windows本身有自己的消息队列. 系统传递消息给应用程序. 应用程序的消息机制:应用程序的执行是通过消息驱动的.消息是整个应用程序的工作引擎. 2.c# ...
- 跨域写cookie
假设a站想往b站写cookie,那么目前有两种方案,参考如下: 第一种(使用jsonp): a站js代码如下: $.ajax({ url: 'http://www.b.com/jsonp.jsp?do ...
- DB2 日志
跟Oracle类似DB2也分为两个模式,日志循环vs归档日志,也就是非归档和归档模式,下面对这两种模式做简单的介绍. 日志循环 日志循环是默认方式,也就是非归档模式,这种模式只支持backup off ...
- slf4j与logback的结合使用
参考:http://my.oschina.net/ydsakyclguozi/blog/412240 一.logback的介绍 Logback是由log4j创始人设计的又一个开源日志组件.logbac ...
- (打补丁 )patch
前言: diff:逐行比较文件的不同,并且显示出来. patch: 打补丁工具,将补丁打到老文件里面,也就是diff左边的那个文件,使得老文件和新文件一样 格式:diff [选项] 老文件 新文件 格 ...
- 转 maven3常用命令、java项目搭建、web项目搭建详细图解
转自地址:http://blog.csdn.net/edward0830ly/article/details/8748986 ------------------------------maven3常 ...