题解 Luogu P1099 【树网的核】
这题是真的水啊。。。
------------
昨天模拟赛考了这题,很多人都是O($n^3$)水过,但我认为,要做就做的足够好(其实是我根本没想到O($n^3$)的做法),然后就开始想O(n)的解法。
首先看题目,前面一大堆看似是废话,其实还是有很大用处的。
问题描述中提到了树的中心,但后面却貌似没有用到,其实中心是给我们带来提示的。
既然是求最小偏心距,那必然是要在直径上找,不然偏心距并不能有过多的减少,所以第一步,定下在直径上找。
然后直径上找也要讲究方法,假如整条路径在中心的左边或右边,那么偏心距就会过大了(s太小了也没办法了)。所以,如果s足够大的话,应该将路径放在中间(指的是路径左端点到直径的左端点与路径右端点到直径右端点的距离差最小),所以先定下中心所在的边上的两个端点(如果s太小就用两端点中靠近中心的一个端点),然后哪一边的偏心距(部分的)大,就往哪边拓展,相同则同时拓展。
有两点需要注意注意:
一、如果有两条或更多直径,走到几条直径的分叉点时,就停止往这边拓展了,并且如果另一边的偏心距(部分的)小于这边,那么就不必拓展了,反正拓展了后偏心距还是这边的值。
二、只有一条直径时,要注意找所选路径上所有的偏心距,然后取大,再与直径两端点到路径两端点的距离取大(这里是指左端点与左端点,右端点与右端点的距离)
然后就愉快的AC了!(实测BZOJ同样能过)
代码如下:(30ms,没进最优解QAQ)
- #include<cstdio>
- inline int read(){
- int r=0,f=1;
- char c=getchar();
- while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
- while(c>='0'&&c<='9')r=(r<<1)+(r<<3)+c-'0',c=getchar();
- return r*f;
- }
- struct E{
- int v,dis,nxt;
- }e[1000001];
- int n,s_e,S,head[500005],dis[500005],s,t,zj,next[2][500005][2],zx[4],f[2][500005],ans=1e9;//f是部分的偏心距,next是从s(或t)出发的下一个点(直径上)
- bool bj[2][500005],jg[500005];//jg就是指直径上的点,bj指的是是不是直径分叉口
- inline int max(int a,int b){
- return a>b?a:b;
- }
- inline int min(int a,int b){
- return a<b?a:b;
- }
- inline void a_e(int u,int v,int dis){
- e[++s_e]=(E){v,dis,head[u]};
- head[u]=s_e;
- }
- void dfs(int p,int fa,int lj){
- dis[p]=lj;
- for(int i=head[p];i;i=e[i].nxt){
- int v=e[i].v;
- if(fa==v)continue;
- dfs(v,p,lj+e[i].dis);
- }
- }
- int dfs_st(int p,int fa,int sta,int end){
- int b=0,d=0;
- if(p==end){
- jg[p]=1;
- return 1;
- }
- for(int i=head[p];i;i=e[i].nxt){
- int v=e[i].v;
- if(fa==v)continue;
- b=max(b,dfs_st(v,p,sta,end));
- if(b==1&&!d)d=i;
- if(f[sta][p]<=f[sta][v]+e[i].dis){
- if(f[sta][p]==f[sta][v]+e[i].dis)bj[sta][p]=1;
- else f[sta][p]=f[sta][v]+e[i].dis,bj[sta][p]=0;
- }
- }
- if(b){
- next[sta][p][0]=e[d].v;
- next[sta][p][1]=e[d].dis;
- jg[p]=1;
- return 1;
- }
- return 0;
- }
- void find_zx(int p,int dis){
- int v=next[0][p][0],val=next[0][p][1];
- if(2*(val+dis)>=zj){
- zx[0]=p,zx[1]=v;
- if(zj-2*dis<=2*(val+dis)-zj)zx[2]=p;//靠近p
- if(zj-2*dis>2*(val+dis)-zj)zx[2]=v;//靠近v
- zx[3]=val;
- return;
- }
- find_zx(v,dis+val);
- }
- int ansl,ansr,anss=-1e9;
- void solve(int l,int r,int dis){
- if(!l||!r)return;
- if(ans>max(f[0][r],f[1][l]))ans=max(f[0][r],f[1][l]),ansl=l,ansr=r;//记录下目前最优左端点与右端点
- if(bj[0][l]||bj[1][l]){//分叉就判断
- if(next[0][r][1]+dis<=S&&f[0][r]>f[1][l])solve(l,next[0][r][0],dis+next[0][r][1]);
- }
- else if(bj[0][r]||bj[1][r]){
- if(next[1][l][1]+dis<=S&&f[0][r]<f[1][l])solve(next[1][l][0],r,dis+next[1][l][1]);
- }
- else {
- if(f[0][r]>f[1][l]&&next[0][r][1]+dis<=S)solve(l,next[0][r][0],dis+next[0][r][1]);
- else if(f[0][r]<f[1][l]&&next[1][l][1]+dis<=S)solve(next[1][l][0],r,dis+next[1][l][1]);
- else if(dis+next[0][r][1]+next[1][l][1]<=S)solve(next[1][l][0],next[0][r][0],dis+next[0][r][1]+next[1][l][1]);
- }
- }
- int find_s(int p,int fa){
- int s=0;
- for(int i=head[p];i;i=e[i].nxt){
- int v=e[i].v;
- if(fa==v||jg[v])continue;//直径上的点不需要找,ans已经记录下最优的了
- s=max(s,find_s(v,p)+e[i].dis);//每个子节点里选最大
- }
- return s;
- }
- void find_ans(int p){
- anss=max(anss,find_s(p,next[1][p][0]));//路径上每个点的部分偏心距取大
- if(p==ansr)return;//到达另一个端点就没什么好找的了
- find_ans(next[0][p][0]);
- }
- int main(){
- freopen("core.in","r",stdin);
- freopen("core.out","w",stdout);
- n=read(),S=read();
- for(int i=1;i<n;i++){
- int u=read(),v=read(),dis=read();
- a_e(u,v,dis);
- a_e(v,u,dis);
- }
- dfs(1,0,0);//找直径
- for(int i=1;i<=n;i++)
- if(dis[s]<dis[i])s=i;
- dfs(s,0,0);//找直径
- for(int i=1;i<=n;i++)
- if(dis[t]<dis[i])t=i;
- zj=dis[t];
- dfs_st(s,0,0,t);//找每个点的偏心距
- dfs_st(t,0,1,s);
- find_zx(s,0);//找直径中心
- if(zx[3]<=S){//能选中心所在的边的两个端点就选
- solve(zx[0],zx[1],zx[3]);
- find_ans(ansl);//以防止有一条直径的情况
- ans=max(ans,anss);
- }
- else ans=max(f[0][zx[2]],f[1][zx[2]]);//不能就找最挨近中心的点的偏心距
- printf("%d",ans);
- return 0;
- }
~~完结偷偷撒花~~✿✿ヽ(°▽°)ノ✿
题解 Luogu P1099 【树网的核】的更多相关文章
- 洛谷 P1099 树网的核
P1099 树网的核 题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W ...
- bzoj1999 / P1099 树网的核
P1099 树网的核 (bzoj数据加强) 前置知识:树的直径 (并不想贴我的智障写法虽然快1倍但内存占用极大甚至在bzoj上MLE) 正常写法之一:用常规方法找到树的直径,在直径上用尺取法找一遍,再 ...
- P1099 树网的核——模拟+树形结构
P1099 树网的核 无根树,在直径上找到一条长度不超过s的路径,使得最远的点距离这条路径的距离最短: 首先两遍dfs找到直径(第二次找的时候一定要吧father[]清零) 在找到的直径下枚举长度不超 ...
- P2491 消防/P1099 树网的核
P2491 消防/P1099 树网的核 双倍经验,双倍快乐. 题意 在一个树上选择一段总长度不超过\(s\)的链使所有点到该链距离的最大值最小. 输出这个最小的值. 做法 Define:以下\(s\) ...
- [NOIP2007] 提高组 洛谷P1099 树网的核
题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并 ...
- #P1099 树网的核 题解
题目描述 pdf 题解 这一题,刚开始看题目感觉好像很难,题目又长……一看数据范围,呵呵. 已经给出来这是个DAG,所以不用担心连通性的问题.那么怎么做呢? 朴素的做法是把树的直径的两个端点都统计出来 ...
- P1099 树网的核
NOIP 2007 提高第四题. 啊......我还是看了题解才做出来的. 这题乍一看毫无头绪,但是我们spy on一下,暗中观察发现:n才300!随便打暴力水过去啊! 然后,这破题怎么暴力?感觉我的 ...
- P1099 树网的核 && P2491 [SDOI2011]消防
给定一棵树, 你可以在树的直径上确定一条长度不超过 \(S\) 的链, 使得树上离此链最长的点距离最小, 输出这个距离 P2491 数据范围为 P1099 的 \(1000\) 倍 Solution ...
- 洛谷P1099 树网的核
传送门 80分 $ Floyd $ 树的直径可以通过枚举求出.直径的两个端点$ maxi,maxj $ ,由此可知对于一个点 $ k $ ,如果满足 $ d[maxi][k]+d[k][maxj]== ...
随机推荐
- listview1 保存和读取 listViewItems保存为txt
/* * 保存原理 * 将LISTVIEW视为一行一行的字符串 * 将所有的行合并成一个字符串 然后保存为TXT文件 ...
- C语言JSON序列化/反序列化
最近想找一个C语言处理嵌套结构体和结构体数组的json库,理想的是能够很容易处理复杂结构体嵌套,并且使用简单的,但是没找到比较合适的,于是打算自己封装一个: 两个问题: C语言结构体本身没有元数据,这 ...
- Oracle通过一个字段的值将一条记录拆分为多条记录
前言 之前遇到了一次这样的需求,当时没有记录,这一次又赶上了,简单的记录一下. 本文个人拙见,若有出入,请指出--来自菜的颤抖 场景 表A中存放了集装箱的信息,一个集装箱一条记录,表B中存放了对于集装 ...
- Spring boot 去除URL 里的 JSESSIONID
方法一 application.yml 里设置 server: port: 80 servlet: session: tracking-modes: cookie cookie: http-only: ...
- python模块中__init__.py的作用
基本概念先上结论举例解释实验一:不包含__init__.py实验二:A中包含__init__.py实验三:A.A_A中也包含__init__.py进阶基本概念概念 解释import 即导入,方式就是在 ...
- Language Modeling with Gated Convolutional Networks(句子建模之门控CNN)--模型简介篇
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/liuchonge/article/deta ...
- MySQL两地三中心方案初步设计【转】
整体内容会按照如下的方式来进行设计: 首先说下方案的背景,我参考了一些资料(参见附件). 方案背景 随着互联网业务快速发展,多IDC的业务支撑能力和要求也逐步提升,行业内的“两地三中心”方案较为流行. ...
- Unexpected token o in JSON at position 1 报错原因
写在前面的话这个问题在之前做项目时碰到过一次,当时按照网上的做法,去掉JSON.parse()这一层转换后就没有这个报错了,数据也能正常使用,就没多想,也没深究是什么原因. 可是这次又碰到了,所以这次 ...
- GIS自定义地理处理工具--极值提取
GIS自定义地理处理工具--极值提取 关键词:最大值提取,最小值提取,极值提取,极小值提取,极大值提取 商务合作,科技咨询,版权转让:向日葵,135—4855__4328,xiexiaokui#qq. ...
- centos sqlite3安装及简单命令
安装:方法一:wget http://www.sqlite.org/sqlite-autoconf-3070500.tar.gztar xvzf sqlite-autoconf-3070500.tar ...