luogu P3761 [TJOI2017]城市 树的直径 bfs
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的更多相关文章
- [TJOI2017] 城市 (树的直径,贪心)
题目链接 Solution 这道题,调了我一晚上... 一直80分 >_<|| ... 考虑到几点: 分开任意一条边 \(u\) ,那么其肯定会断成两棵树. 肯定是分开直径上的边最优,否则 ...
- poj2631 树的直径 + bfs
//Accepted 492 KB 0 ms //树的直径 bfs #include <cstdio> #include <cstring> #include <iost ...
- [洛谷P3761] [TJOI2017]城市
洛谷题目链接:[TJOI2017]城市 题目描述 从加里敦大学城市规划专业毕业的小明来到了一个地区城市规划局工作.这个地区一共有ri座城市,<-1条高速公路,保证了任意两运城市之间都可以通过高速 ...
- bzoj4890[Tjoi2017]城市(树的半径)
4890: [Tjoi2017]城市 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 149 Solved: 91[Submit][Status][D ...
- hdu2196 树的直径 + bfs
//Accepted 740 KB 15 ms //树的直径 //距离一个顶点最远的点一定是树的直径的一个端点 #include <cstdio> #include <cstring ...
- [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分
题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...
- LG5536 「XR-3」核心城市 树的直径
问题描述 LG5536 题解 两次 \(\mathrm{dfs}\) 求树的直径. 然后找到树的直径的中点. 然后按照 子树中最深的点深度-自己深度 排序,贪心选取前 \(k\) 个. \(\math ...
- 树上选两点(使最短)树的直径+bfs
题意: 给你一颗树,让你放两个点,放在哪里的时候任意点到某个最近的消防站最远值最小. 思路: 树的直径类题目. 首先我们想两个点会把整棵树分成两个团,所以肯定会在树的某个链上切开. 而且要切一定切在树 ...
- ZOJ 3820 Building Fire Stations 求中点+树的直径+BFS
题意:给一棵树,要求找出两个点,使得所有点到这两个点中距离与自己较近的一个点的距离的最大值(所有点的结果取最大的值,即最远距离)最小. 意思应该都能明白. 解法:考虑将这棵树摆直如下: 那么我们可以把 ...
随机推荐
- css条纹背景样式、及方格斜纹背景的实现
一.横向条纹如下代码: background: linear-gradient(#fb3 %, #58a %) 上面代码表示整个图片的上部分20%和下部分20%是对应的纯色,只有中间的部分是渐变色.如 ...
- swiper的自适应高度问题
#swiper的自适应高度问题 众所周知,swiper组件的元素swiper-item是设置了绝对定位的,所以里面的内容是无法撑开swiper的,并且给swiper盒子设置overflow:vis ...
- Vue数据检监测问题
vue.js是通过数据劫持的方式实现数据的双向绑定的,其中过程如下: 当把一个JavaScript对象传给Vue实例的data选项时,Vue会遍历此对象的所有属性并使用 Object.definePr ...
- 数据可视化基础专题(二):Pandas基础(一) excel导入与导出
1.Excel 1.1 Excel导入 read_excel() pandas.read_excel(io, sheet_name=0, header=0, names=None, index_col ...
- redis(十七):Redis 安装,部署(WINDOWS环境下)
1.下载Redis安装文件, 我选择的是 3.0.504 版本,有zip或msi可供下载. 2.解压缩后,打开安装目录 双击redis-server.exe启动redis服务器,双击redis-c ...
- 数据可视化之 图表篇(四) 那些精美的Power BI可视化图表
之前使用自定义图表,每次新打开一个新文件时,都需要重新添加,无法保存,在PowerBI 6月更新中,这个功能得到了很大改善,可以将自定义的图表固定在内置图表面板上了. 添加自定义图表后,右键>固 ...
- 数据可视化之powerBI技巧(二十二)利用这个方法,帮你搞定Power BI"增量刷新"
Power BI的增量刷新功能现在已经对Pro用户开通,但由于种种限制,很多人依然无法使用无这个功能,所以,每一次刷新,都要彻底更新数据集.这对于量级比较大的数据集来说,着实是一件耗费时间的事情. 拿 ...
- Python Hacking Tools - Vulnerability Scanner
Security Header website: https://securityheaders.com/ Scan the target website: https://www.hackthiss ...
- select、poll和epoll之间的区别
在深入理解select.poll和epoll之间的区别之前,首先要了解什么是IO多路复用模型. IO多路复用 简单来说,IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备就绪,它就通知该进 ...
- 自已动手作图搞清楚AVL树
@ 目录 一.背景 二.平衡二分搜索树---AVL树 2.1 AVL树的基本概念 结点 高度 平衡因子 2.2 AVL树的验证 三.旋转操作 3.1 L L--需要通过右旋操作 3.2 R R--需要 ...