LINK:城市

谢邀,学弟说的一道毒瘤题。

没有真正的省选题目毒瘤 或者说 写O(n)的做法确实毒瘤。

这里给一个花20min就写完的非常好写的暴力。

容易想到枚举哪条边删掉 删掉之后考虑在哪两个点上加。

一个比较重要的性质是 联通两个连通块之后 大联通块的直径端点一定有一端属于原来两个联通块的直径端点之一。

也就是合并两个连通块 直径等于=max(左边直径,右边直径,链接起来的直径)

其中前两者固定 考虑让第三者最小 进一步可以分析得到 那两个点的贡献是到自己连通块内的最长距离的点。

分别最小化之后显然是直径上的中点。

一个比较有意思的事实:实际上直径的中点可能在两个节点之间 那么此时这两个节点的贡献相同 所以选哪个都行。

沿着直径找中点过于繁琐 可以直接从直径两端bfs 然后每个点的贡献为max(dis1[x],dis2[x]).

这样就很好写了。值得一提的是 我的写法没有加入过多的优化 每次需要6遍bfs,所以常数有点大。

卡常:容易发现 如果删的不是直径上的边那么对答案没有贡献 可以直接枚举删直径上的边。

考虑求出左边的直径之后进行最优性剪枝 比当前答案大就没必要再做了。

进一步的可以将bfs的次数卡一下 只删直径上的边之后 一个比较重要的性质是 原来树中的直径依然还是分属两个连通块的两端。

这样bfs的次数只有4次了。

进一步的 可以由此推出O(n)的做法 沿着直径删边 然后 每次便利多出来的部分 由上次直径推出当前直径 复杂度就降到O(n)了 不过实现起来过于繁琐 我就没实现。

经过优化的code:n^2 十个测试点跑了400多ms 我也很骄傲~

const int MAXN=5010;
int n,ans,id,flag,len=1,t,h,c1,c2;
int vis[MAXN],c[MAXN<<1],dis[MAXN],q[MAXN],dis1[MAXN],s1,s2,s3,mark;
int lin[MAXN],e[MAXN<<1],ver[MAXN<<1],nex[MAXN<<1];
inline void add(int x,int y,int z)
{
ver[++len]=y;
nex[len]=lin[x];
lin[x]=len;
e[len]=z;
}
inline int bfs(int s)
{
++id;t=h=0;int mx=0,p=s;
q[++t]=s;vis[s]=id;dis[s]=0;
while(++h<=t)
{
int x=q[h];
go(x)
{
if(i==(mark^1)||i==mark)continue;
if(vis[tn]!=id)
{
vis[tn]=id;
dis[tn]=dis[x]+e[i];
q[++t]=tn;
if(dis[tn]>mx)mx=dis[tn],p=tn;
}
}
}
return p;
}
inline void bfs1(int s,int &w)
{
++id;t=h=0;w=INF;
q[++t]=s;vis[s]=id;dis1[s]=0;
while(++h<=t)
{
int x=q[h];
w=min(w,max(dis[x],dis1[x]));
go(x)
{
if(i==(mark^1)||i==mark)continue;
if(vis[tn]!=id)
{
vis[tn]=id;
dis1[tn]=dis1[x]+e[i];
q[++t]=tn;
}
}
}
}
inline void dfs(int x,int fa)
{
if(x==c2){flag=1;return;}
go(x)
if(tn!=fa)
{
dfs(tn,x);
if(flag)
{
c[i]=c[i^1]=1;
return;
}
}
}
int main()
{
freopen("1.in","r",stdin);
get(n);
rep(2,n,i)
{
int get(x),get(y),get(z);
add(x,y,z);add(y,x,z);
}
c1=bfs(1);c2=bfs(c1);
dfs(c1,0);ans=dis[c2];
for(int i=2;i<=len;i+=2)
{
if(!c[i])continue;
mark=i;
int w1=bfs(c1);
if(dis[w1]>=ans)continue;
bfs1(w1,s1);
int w2=bfs(c2);
if(dis[w2]>=ans)continue;
bfs1(w2,s2);
ans=min(ans,max(dis[w1],max(dis[w2],s2+s1+e[i])));
}
put(ans);return 0;
}

luogu P3761 [TJOI2017]城市 树的直径 bfs的更多相关文章

  1. [TJOI2017] 城市 (树的直径,贪心)

    题目链接 Solution 这道题,调了我一晚上... 一直80分 >_<|| ... 考虑到几点: 分开任意一条边 \(u\) ,那么其肯定会断成两棵树. 肯定是分开直径上的边最优,否则 ...

  2. poj2631 树的直径 + bfs

    //Accepted 492 KB 0 ms //树的直径 bfs #include <cstdio> #include <cstring> #include <iost ...

  3. [洛谷P3761] [TJOI2017]城市

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

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

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

  5. hdu2196 树的直径 + bfs

    //Accepted 740 KB 15 ms //树的直径 //距离一个顶点最远的点一定是树的直径的一个端点 #include <cstdio> #include <cstring ...

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

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

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

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

  8. 树上选两点(使最短)树的直径+bfs

    题意: 给你一颗树,让你放两个点,放在哪里的时候任意点到某个最近的消防站最远值最小. 思路: 树的直径类题目. 首先我们想两个点会把整棵树分成两个团,所以肯定会在树的某个链上切开. 而且要切一定切在树 ...

  9. ZOJ 3820 Building Fire Stations 求中点+树的直径+BFS

    题意:给一棵树,要求找出两个点,使得所有点到这两个点中距离与自己较近的一个点的距离的最大值(所有点的结果取最大的值,即最远距离)最小. 意思应该都能明白. 解法:考虑将这棵树摆直如下: 那么我们可以把 ...

随机推荐

  1. 状压DP之愤怒的小鸟

    题目 传送们P2831 题目较长,不加以赘述 直接步入正题 首先是数学知识,我们可以先根据给出的任意两只猪构建相应的抛物线,同时再构建完之后应判断抛物线的合法性(比如a小于0啊,等等),公式推演就不在 ...

  2. AT2272 [ARC066B] Xor Sum 题解

    题目连接:传送门 分析 这道题只看题目中给的样例是找不出规律的 所以我们可以打一下表 1, 2, 4, 5, 8, 10, 13, 14, 18 如果你还是没有看出什么规律的话,我们可以从OEIS上搜 ...

  3. HTTP响应头拆分/CRLF注入详解

    转自:https://blog.csdn.net/gstormspire/article/details/8183598 https://blog.csdn.net/cqf539/article/de ...

  4. 概率图模型(CPD)(二)

    CPD是conditional probability distribution的缩写,翻译成中文叫做 条件概率分布.在概率图中,条件概率分布是一个非常重要的概念.因为概率图研究的是随机变量之间的练习 ...

  5. 微信小程序热更新,小程序提示版本更新,版本迭代,强制更新,微信小程序版本迭代

    相信很多人在做小程序的时候都会有迭代每当版本迭代的时候之前老版本的一些方法或者显示就不够用了这就需要用到小程序的热更新.或者说是提示升级小程序版本 editionUpdate:function(){ ...

  6. 德布鲁因序列与indexing 1

    目录 写在前面 标记left-most 1与right-most 1 确定位置 德布鲁因序列(De Bruijn sequence) 德布鲁因序列的使用 德布鲁因序列的生成与索引表的构建 参考 博客: ...

  7. 适用于IE8浏览器的bootsarp下拉菜单(支持多选,全选)

    html部分代码,引用及整体项目Github项目地址:https://github.com/CNbozi/combobox 1 <!DOCTYPE html> <html lang= ...

  8. Spring AOP里的静态代理和动态代理,你真的了解嘛?

    什么是代理? 为某一个对象创建一个代理对象,程序不直接用原本的对象,而是由创建的代理对象来控制原对象,通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为 ...

  9. echarts 实战 : 图表竖着或横着是怎样判定的?

    这个问题比较简单. echarts 的图表默认是竖着的. 只要 xAxis 和 yAxis 互换,竖着的图就变成了横着的图了. 所以我们可以可以写一个xy轴互换的方法. reverseXYAxis = ...

  10. PyQt5绘图

    QPainter 功能:QPainter实现在QWidget上画图功能 说明:绘图必须在paintEvent中完成,且要在bengin和end之间作图 接口: 方法 描述 begin 开始画图 end ...