博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codeforces379 F. New Year Tree
阅读量:5220 次
发布时间:2019-06-14

本文共 2980 字,大约阅读时间需要 9 分钟。

出处: Codeforces

主要算法:LCA+树的直径

难度:4.4

思路分析:

  给出q个操作,每次在一个节点上接上两个叶子。每一次询问树的直径。

  暴力做法:每一次操作暴力BFS两遍……然而……复杂度时\(O(Q * 2n\),爆到不知哪里去了。

  其实我们会发现,除非新加进来的两个点能够对直径产生影响,直径根本不会变。所以我们只需要考虑新加进来的点对原图的影响。

  那么如何操作呢?先假设没经过任何操作之前,直径的端点时2和3(事实上2,3,4中任意两个都可以),设直径的端点1为A,端点2为B。每加进来两个点x,y时,若dist(x,A)或dist(x,B)大于原先的直径,则用它们更新,并且将直径的另一个端点设置为x或y。

  下面来证明这样的做法的正确性:

  由于在讲树的直径的时候我们提到过,从任意一个点出发进行BFS,所能到达的最远点一定是树的一个直径之一。

  先假设新加进来的两个点x,y不存在,那么原先的树的直径就是A->B,并且一定是最长的了。设x,y的父亲节点为v。那么从v所能到达的最远的点一定是A或B。并且x或y到v的距离只有1,也只能是1。所以从x或y出发遍历所能够到达的最远的点一定也是A或B。而由于之前的直径是最长的,所以我当前的直径要比上一轮更长,只能是加了一,而这个1就是从x或y到v的距离的距离中产生的。

  所以我们选择x来更新(因为x和y其实是一样的,你不可能有一条直径是从x到y的,因为这样只能是2,而刚开始就已经是2了)。分别求出x到A与B的距离,如果x到A更新成功,则B=x;如果x到B更新成功,则A=x;事实上,它们只有一个能更新成功。

  于是现在问题就转化为了求两点之间距离了,LCA随便搞一搞就好了。这题还不用Dfs预处理,真是太可爱了……

代码注意点:

  由于有q次操作,每次操作增加两个点,所以点的数目是\(2q+4\),而不是\(q+4\)

Code

/** This Program is written by QiXingZhi **/#include 
#include
#include
#include
#define r read()#define Max(a,b) (((a)>(b)) ? (a) : (b))#define Min(a,b) (((a)<(b)) ? (a) : (b))using namespace std;typedef long long ll;const int N = 1000100;const int INF = 1061109567;inline int read(){ int x = 0; int w = 1; register int c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); return x * w;}vector
G[N];int dep[N],f[N][30];int Q,v,cur_node,A,B,cur1,cur2,ans,Tmp_Dist;inline void AddEdge(int u, int v){ G[u].push_back(v); G[v].push_back(u);}inline void Init(){ AddEdge(1,2), AddEdge(1,3), AddEdge(1,4); cur_node = 4; A = 2, B = 3; ans = 2; f[2][0] = f[3][0] = f[4][0] = 1; dep[1] = 1; dep[2] = dep[3] = dep[4] = 2;}inline void Update(int u, int v){ f[v][0] = u; dep[v] = dep[u] + 1; for(int i = 1; (1<
<= dep[v]; ++i){ f[v][i] = f[f[v][i-1]][i-1]; }}inline int LCA(int _a, int _b){ if(dep[_a] < dep[_b]){ swap(_a, _b); } int a = _a, b = _b; for(int i = 25; i >= 0; --i){ if(dep[a] - (1<
< dep[b]) continue; a = f[a][i]; } if(a == b) return a; for(int i = 25; i >= 0; --i){ if(f[a][i] == f[b][i]) continue; a = f[a][i]; b = f[b][i]; } return f[a][0];}inline int GetDist(int _a, int _b){ int __lca = LCA(_a, _b); return dep[_a]-dep[__lca]+dep[_b]-dep[__lca];}int main(){ Init(); Q = r; while(Q--){ v = r; AddEdge(v,++cur_node); Update(v,cur_node); AddEdge(v,++cur_node); Update(v,cur_node); cur1 = cur_node; Tmp_Dist = GetDist(cur1,A); if(Tmp_Dist > ans){ ans = Tmp_Dist; B = cur1; } Tmp_Dist = GetDist(cur1,B); if(Tmp_Dist > ans){ ans = Tmp_Dist; A = cur1; } printf("%d\n",ans); }/* for(int i = 1; i <= cur_node; ++i){ for(int j = 0; j <= 3; ++j){ printf("f[%d][%d] = %d\n",i,j,f[i][j]); } } for(int i = 1; i <= cur_node; ++i){ printf("dep[%d] = %d\n",i,dep[i]); }*/ return 0;}

 

转载于:https://www.cnblogs.com/qixingzhi/p/9309102.html

你可能感兴趣的文章
18款在线代码片段测试工具
查看>>
20.C++- &&,||逻辑重载操作符的缺陷、,逗号重载操作符的分析
查看>>
静态变量数组实现LRU算法
查看>>
在SQL中怎么把一列字符串拆分为多列
查看>>
中文系统 上传file的input显示英文
查看>>
css样式写一个三角形
查看>>
比callback更简洁的链式执行promise
查看>>
android permission
查看>>
【译】在Asp.Net中操作PDF - iTextSharp - 使用字体
查看>>
事务备份还原分离附加
查看>>
JSch - Java实现的SFTP(文件上传详解篇)
查看>>
一些注意点
查看>>
.net 文本框只允许输入XX,(正则表达式)
查看>>
[BSGS][哈希]luogu P3846 可爱的质数
查看>>
Python 第四十五章 MySQL 内容回顾
查看>>
iostat参数说明
查看>>
Python-Mac 安装 PyQt4
查看>>
P2571 [SCOI2010]传送带
查看>>
实验2-2
查看>>
String,StringBuffer与StringBuilder的区别?? .
查看>>