Codeforces题号:#379F

出处: 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 <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#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 = ;
const int INF = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) +(x << ) + c - '', c = getchar();
return x * w;
}
vector <int> G[N];
int dep[N],f[N][];
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(,), AddEdge(,), AddEdge(,);
cur_node = ;
A = , B = ;
ans = ;
f[][] = f[][] = f[][] = ;
dep[] = ;
dep[] = dep[] = dep[] = ;
}
inline void Update(int u, int v){
f[v][] = u;
dep[v] = dep[u] + ;
for(int i = ; (<<i) <= dep[v]; ++i){
f[v][i] = f[f[v][i-]][i-];
}
}
inline int LCA(int _a, int _b){
if(dep[_a] < dep[_b]){
swap(_a, _b);
}
int a = _a, b = _b;
for(int i = ; i >= ; --i){
if(dep[a] - (<<i) < dep[b]) continue;
a = f[a][i];
}
if(a == b) return a;
for(int i = ; i >= ; --i){
if(f[a][i] == f[b][i]) continue;
a = f[a][i];
b = f[b][i];
}
return f[a][];
}
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 ;
}

Codeforces379 F. New Year Tree的更多相关文章

  1. 2018 Multi-University Training Contest 3 Problem F. Grab The Tree 【YY+BFS】

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=6324 Problem F. Grab The Tree Time Limit: 2000/1000 MS ...

  2. Codeforces 379 F. New Year Tree

    \(>Codeforces \space 379 F. New Year Tree<\) 题目大意 : 有一棵有 \(4\) 个节点个树,有连边 \((1,2) (1,3) (1,4)\) ...

  3. 2014 Super Training #9 F A Simple Tree Problem --DFS+线段树

    原题: ZOJ 3686 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3686 这题本来是一个比较水的线段树,结果一个ma ...

  4. 【2013 ICPC亚洲区域赛成都站 F】Fibonacci Tree(最小生成树+思维)

    Problem Description Coach Pang is interested in Fibonacci numbers while Uncle Yang wants him to do s ...

  5. 2018HDU多校训练-3-Problem F. Grab The Tree

    Little Q and Little T are playing a game on a tree. There are n vertices on the tree, labeled by 1,2 ...

  6. Problem F. Grab The Tree HDU - 6324

    题意:给出一棵n个节点的树,每个节点有一个权值,Q和T玩游戏,Q先选一些不相邻的节点,T选剩下的节点,每个人的分数是所选节点的权值的异或和,权值大的胜出,问胜出的是谁. 题解: 话说,这题后面的边跟解 ...

  7. AtCoder Grand Contest 023 F - 01 on Tree

    Description 题面 Solution HNOI-day2-t2 复制上去,删点东西,即可 \(AC\) #include<bits/stdc++.h> using namespa ...

  8. 泛函编程(8)-数据结构-Tree

    上节介绍了泛函数据结构List及相关的泛函编程函数设计使用,还附带了少许多态类型(Polymorphic Type)及变形(Type Variance)的介绍.有关Polymorphism的详细介绍会 ...

  9. codeforces 675D D. Tree Construction(线段树+BTS)

    题目链接: D. Tree Construction D. Tree Construction time limit per test 2 seconds memory limit per test ...

随机推荐

  1. Java Arrays工具类的使用

    Arrays 类 java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的.具有以下功能: 给数组赋值:通过fill方法. 对数组排序:通过sort方法,按升序. 比较数组:通过 ...

  2. P2P平台介绍

    https://www.ludou.org/tutengdai.html https://www.tutengdai.com/register?invite_code=9991300

  3. c++之sizeof的用法

    在此温习一下c语言中sizeof的用法以及c++11.0的标准中,关于初始化的新方式,先上代码: # include "iostream" # include "stri ...

  4. jQuery基础语法知识梳理

    一.attr() attr()方法设置或返回元素的属性. attr(属性名):获取元素属性名的值. attr(属性名,属性值):设置元素属性名的值. 例子: <a href=”http://12 ...

  5. linux中mariadb的安装

    在Linux中mariaDB的安装 MariaDB其实就是MySQL的分支,是为了应对MySQL的即将的闭源风险所产生的. Linux系统中软件包的格式为mysql.rpm格式. 通过yum去安装 L ...

  6. HDU 2006 求奇数的乘积

    http://acm.hdu.edu.cn/showproblem.php?pid=2006 Problem Description 给你n个整数,求他们中所有奇数的乘积.   Input 输入数据包 ...

  7. PHP Lumen Call to a member function connection() on null 报错

    (1/1) Error Call to a member function connection() on nullin Model.php line 1201at Model::resolveCon ...

  8. Java Integer 与 int 深刻理解

    今天在做Object 自动转为Integer 类型之后的判断,遇到一个不理解的点,当数值超过127之后,两个数值相同的Object 对象用 == 判断的结果是false. Object a = 128 ...

  9. [官网]How to configure the Microsoft Distributed Transaction Coordinator (MSDTC) on Linux

    How to configure the Microsoft Distributed Transaction Coordinator (MSDTC) on Linux APPLIES TO: SQL ...

  10. linux之ssh互信

    1.如果你是之作root用户互信的话,直接一路执行如下命令就行. 1.切换你需要互信的账户 su hadoop1 2.执行命令,一路回车即可(在当前用的宿主用户目录下的.ssh目录下生成公钥和秘钥id ...