题目链接


Solution

这道题,调了我一晚上... 一直80分 >_<|| ...

考虑到几点:

  • 分开任意一条边 \(u\) ,那么其肯定会断成两棵树.
  • 肯定是分开直径上的边最优,否则原树上最长的边仍然会存在. 其新树直径只有可能更大.
  • 令两棵子树的直径分别为 \(dist_1,dist_2\) ,选取的两个点分别为 \(x_1,x_2.\)

    其达到两棵子树的最远距离分别为 \(dis_1,dis_2\).

    那么组成的新树直径即为:
    \[max(dist_1,dist_2,dis_1+dis_2+w_u)
    \]


所以我们先枚举断开直径上的边,然后分别找到断开后两棵子树的直径.

接着我们讨论 \(dis_1,dis_2\) 最优情况.

  1. 其 \(dis\) 为其到子树直径较远的一端.
  2. 如果 \(x_1,x_2\) 在子树的直径上,那么显然会更优,因为如果不在直径上,它还会多出一小段距离.
  3. 然后就可以考虑在直径上的话,显然取直径的中点(如果有的话)会最优,因为此时相当于平分直径,然后使得可能的答案尽量小了.
  4. 如果没有直径中点的话,那么我们可以找到一条“中边”,使得其断开的直径两端距离之差最小.

那么我们找的策略也就出来了.直接找到两棵子树上直径的 "中边",然后对两条中边上的四个点进行讨论选取即可.


Code

#include<bits/stdc++.h>
#define ll long long
const ll inf=192608173;
using namespace std;
const int maxn=5008;
struct sj{int to,next;ll w;}
a[maxn*2];
int head[maxn],size;
int v[maxn],now[maxn];
int road[maxn],road1[maxn];
int n,num,cntt,cnt,x,y,w;
ll nowdis,maxx,ans=inf;
ll xx[maxn],xx1[maxn],dis[maxn];
ll dis1,dis2,dis3,dis4; int read()
{
int f=1,w=0; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){w=w*10+ch-'0';ch=getchar();}
return f*w;
} void add(int x,int y,int w)
{
a[++size].to=y;
a[size].next=head[x];
head[x]=size;
a[size].w=w;
} void dfs(int x)
{
v[x]=1;now[++num]=x;
for(int i=head[x];i;i=a[i].next)
{
int tt=a[i].to;
if(!v[tt])
{
nowdis+=a[i].w;
dis[num]=a[i].w;
dfs(tt);
nowdis-=a[i].w;
}
}
if(nowdis>maxx)
{
maxx=nowdis; cnt=num;
for(int i=1;i<=cnt;i++)
road[i]=now[i],xx[i]=dis[i];
//每一次 road 都是找出来的临时最长边.
}
v[x]=0; num--;return;
} int main()
{
n=read();
for(int i=1;i<n;i++)
{
x=read(); y=read(); w=read();
add(x,y,w);
add(y,x,w);
}
dfs(1); dfs(road[cnt]); cntt=cnt;
for(int i=1;i<=cnt;i++)
road1[i]=road[i],xx1[i]=xx[i];
//xx1为原直径上的边长度,road1为原直径上的点.
for(int i=1;i<cntt;i++)
{
ll x1=0,x2=0,maxx1,maxx2;
dis1=dis2=dis3=dis4=0; v[road1[i+1]]=1; maxx=-1;
//给右边打上标记,让他仅在左边的子树中查询
dfs(road1[i]);
dfs(road[cnt]);
maxx1=maxx;
for(int j=1;j<cnt;j++)
{
x1+=xx[j];
if(x1>maxx1-x1)
{dis1=x1,dis2=maxx1-x1+xx[j];break;}
}
//找到"中边" v[road1[i]]=1; maxx=-1;
//给左边打上标记
dfs(road1[i+1]);
dfs(road[cnt]);
maxx2=maxx;
for(int j=1;j<cnt;j++)
{
x2+=xx[j];
if(x2>maxx2-x2)
{dis3=x2,dis4=maxx2-x2+xx[j];break;}
}
v[road1[i]]=0; ans=min(ans,max(dis1+dis3+xx1[i],max(maxx1,maxx2)));
ans=min(ans,max(dis1+dis4+xx1[i],max(maxx1,maxx2)));
ans=min(ans,max(dis2+dis3+xx1[i],max(maxx1,maxx2)));
ans=min(ans,max(dis2+dis4+xx1[i],max(maxx1,maxx2)));
}
cout<<ans<<endl;
}

[TJOI2017] 城市 (树的直径,贪心)的更多相关文章

  1. luogu P3761 [TJOI2017]城市 树的直径 bfs

    LINK:城市 谢邀,学弟说的一道毒瘤题. 没有真正的省选题目毒瘤 或者说 写O(n)的做法确实毒瘤. 这里给一个花20min就写完的非常好写的暴力. 容易想到枚举哪条边删掉 删掉之后考虑在哪两个点上 ...

  2. bzoj4890[Tjoi2017]城市(树的半径)

    4890: [Tjoi2017]城市 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 149  Solved: 91[Submit][Status][D ...

  3. [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分

    题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...

  4. Sonya and Ice Cream CodeForces - 1004E 树的直径, 贪心

    题目链接 set维护最小值贪心, 刚开始用树的直径+单调队列没调出来... #include <iostream>#include <cstdio> #include < ...

  5. LG5536 「XR-3」核心城市 树的直径

    问题描述 LG5536 题解 两次 \(\mathrm{dfs}\) 求树的直径. 然后找到树的直径的中点. 然后按照 子树中最深的点深度-自己深度 排序,贪心选取前 \(k\) 个. \(\math ...

  6. cf 911F 树的直径+贪心

    $des$ 给定一棵 n 个节点的树,你可以进行 n ? 1 次操作,每次操作步骤如下:选择 u,v 两个度数为 1 的节点.将 u,v 之间的距离加到 ans 上.将 u 从树上删除.求一个操作序列 ...

  7. [SDOI2013]直径 (树的直径,贪心)

    题目链接 Solution 我们直接找到一条直径 \(s\),起点为 \(begin\),终点为 \(end\). 从前往后遍历点 \(u\) ,若子树中最大的距离与 \(dis(u,begin)\) ...

  8. CF911F Tree Destruction (树的直径,贪心)

    题目链接 Solution 1.先找出树的直径. 2.遍历直径沿途的每一个节点以及它的子树. 3.然后对于每个非直径节点直接统计答案,令直径的两个端点为 \(x_1,x_2\) . \[Ans=\su ...

  9. 换根DP+树的直径【洛谷P3761】 [TJOI2017]城市

    P3761 [TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速公 ...

随机推荐

  1. s///|s()()i|/i|/g|\U|\u|\L|\l|\U\l|split|join|匹配到hash|匹配到变量|`date`|$^I

    #!/usr/bin/perl -w use strict; use warnings; $_='She is a good girl and likes helping others '; s/sh ...

  2. Java(面试题):字符串截取

    在Java中,字符串“abcd”与字符串“ab你好”的长度是一样,都是四个字符. 但对应的字节数不同,一个汉字占两个字节. 定义一个方法,按照指定的字节数来取子串. 如:对于“ab你好”,如果取三个字 ...

  3. 类库日期和jsp导包

    一.日期类库 1.1. Date Date类创建一个时间,或者是创建一个与你计算机当前的时间:精确到毫秒. //实例化时间类 Date date = new Date(); 1.2.格式转换类 1.2 ...

  4. linux虚拟机配置网络

    第一步.网络模式设置为桥接模式   第二步.设置ip和掩码 vim /etc/sysconfig/network-scripts/ifcfg-ens33 ens33为当前机器的网卡名称  在文件尾部添 ...

  5. DD命令做备份和恢复

    正确的备份方法是先挂载移动硬盘分区:mount /dev/sdb5 /mnt 然后再备份:dd if=/dev/sda of=/mnt/backup_sda.img 恢复时同样要先挂载,再恢复:mou ...

  6. UML类图中的六种线条与六种关系

    1.泛化(generalize) 实线空心三角箭头. 2.实现(realize) 虚线空心三角箭头. 3.聚合(aggregation) 实线空心菱形箭头. 4.组合(composition) 实线实 ...

  7. NOIP2018

    非常糟糕.从未意识到过考场debuff这么严重. 果不其然,高档选手强如txc实力AK:而像我这样的中档选手就是重在考场发挥和自我调整了吧. 究竟要付出多少代价才能领会一个教训 看来要尝试更自闭一点

  8. Python数据分析实战视频教程【小蚊子数据分析实战课程】

    点击了解更多Python课程>>> Python数据分析实战视频教程[小蚊子数据分析实战课程] [课程概述] Python数据分析实战' 适用人群:适合需提升竞争力.提升工作效率.喜 ...

  9. 【js】input 焦点到内容的最后

     //引用部分应支持jQuery  function find_focus(obj){    var curr = jQuery(obj);    var val = curr.val();    c ...

  10. ubuntu 16.04下如何打造 sublime python编程环境

    一.安装python3     ubuntu自身是安装python2的,例如在ubuntu 16.04中安装的就是python2.7.但我想在python3的环境下进行开发所以就要安装python3. ...