• Codeforces 379 F. New Year Tree


    ## [$>Codeforces space 379 F. New Year Tree<$](http://codeforces.com/problemset/problem/379/F)

    题目大意 : 有一棵有 (4) 个节点个树,有连边 ((1,2) (1,3) (1,4)) ,一共有 (q) 次操作,每次选择一个节点,新建两个节点 (n + 1, n + 2) 向其连边,每次操作完之后求树的直径的长度

    $1 leq q leq 5 imes 10^5 $

    解题思路 :

    观察发现,每次加点后,树的直径的端点至多只会变化一个

    证明:首先显然新的直径的端点不可能是两个新加的点,也不可能是两个原本不是直径端点的点

    所以如果要使得新的直径的端点变化两个的话,那么必然有一个端点是新加的点

    假设有新加的点 (u) ,其父亲是 (fa) ,离 (fa) 最远的点一定是树的直径的一个端点,那么此时离 (u) 最远的点也一定是树的直径一个端点. 至此产生矛盾,所以每次加点后,树的直径的端点至多只会变化一个

    所以只需要每次加点动态维护倍增数组,用 (lca) 暴力判是否能更新掉一个直径端点即可,复杂度是 (O(nlogn))


    /*program by mangoyang*/
    #include<bits/stdc++.h>
    #define inf (0x7f7f7f7f)
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    typedef long long ll;
    using namespace std;
    template <class T>
    inline void read(T &x){
        int f = 0, ch = 0; x = 0;
        for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
        for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
        if(f) x = -x;
    }
    #define N (1000005)
    int f[N][23], dep[N], tot; 
    inline void addson(int u){
    	int v = ++tot; 
    	dep[v] = dep[u] + 1, f[v][0] = u;
    	for(int j = 1; j <= 22; j++) f[v][j] = f[f[v][j-1]][j-1];
    }
    inline int Lca(int x, int y){
    	if(dep[x] < dep[y]) swap(x, y);
    	for(int i = 22; i >= 0; i--){
    		if(dep[f[x][i]] >= dep[y]) x = f[x][i];
    		if(dep[x] == dep[y]) break;
    	}
    	if(x == y) return x;
    	for(int i = 22; i >= 0; i--)
    		if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
    	return f[x][0];
    }
    inline int dis(int x, int y){
    	int lca = Lca(x, y); return dep[x] + dep[y] - 2 * dep[lca];	
    }
    int main(){
    	dep[2] = dep[3] = dep[4] = 1;
    	f[2][0] = f[3][0] = f[4][0] = 1, tot = 4;
    	int n, l = 2, r = 4, ans = 2;
    	read(n);
    	for(int i = 1; i <= n; i++){
    		int x; read(x);
    		addson(x), addson(x);
    		int nl = tot - 1, nr = tot;
    		int s1 = dis(nl, r), s2 = dis(nl, l);
    		int s3 = dis(nr, l), s4 = dis(nr, r);
    		ans = Max(ans, Max(Max(s1, s2), Max(s3, s4)));
    		if(ans == s1) l = nl;
    		else if(ans == s2) r = nl;
    		else if(ans == s3) r = nr;
    		else if(ans == s4) l = nr;
    		printf("%d
    ", ans); 
    	}	
    	return 0;
    }
    
  • 相关阅读:
    sudo 临时切换用户和环境变量的传递
    递归复杂度算法如何计算草稿
    Mac下设计全局环境变量
    Golang http 超时设置方法
    go get github竟然区分大小写
    通过远程终端后台运行程序
    打开华为手机的logcat
    Golang的锁和线程安全的Map
    PL/SQL语句块基本语法(ORACLE存储过程,函数,包,游标) (转)
    C# 文件操作把结果保存到文件里
  • 原文地址:https://www.cnblogs.com/mangoyang/p/9356990.html
Copyright © 2020-2023  润新知