• Codeforces 911F Tree Destruction(贪心 && 树的直径)


    题目链接  Tree Destructi

    题意  给定一棵树,每次可以选定树上的两个叶子,并删去其中的一个。答案每次加上两个选定的叶子之间的距离。

      求最后答案的最大值。

     

    首先求出树的某一条直径,令其端点分别为L, R。

    把L看成树的根,那么R一定是叶子结点。

    对于那些非直径上的点,离他们最远的点肯定是L或R中的一个(可能也有其他的,但是L或R肯定已经最大了)

    所以依次把这些非直径上的点删掉,删掉的时候在L和R中选择一个就行了。

    最后把直径删掉即可。

    时间复杂度$O(nlogn)$  (应该是可以做到$O(n)$的,但是我比较懒)

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    typedef long long LL;
    
    const int N = 2e5 + 10;
    
    vector <int> v[N];
    
    int n;
    int cnt;
    int x, y;
    int L, R;
    
    int f[N][20];
    int a[N];
    int deep[N], father[N];
    int Father[N];
    int vis[N];
    int c[N];
    int isroot[N];
    
    LL ans = 0;
    
    queue <int> q;
    
    void dfs(int x, int fa, int now){
    	deep[x] = now;
    	if (fa){
    		f[x][0] = fa;
    		for (int i = 0; f[f[x][i]][i]; ++i)
    			f[x][i + 1] = f[f[x][i]][i];
    	}
    
    	if (now > cnt) cnt = now, L = x;
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		dfs(u, x, now + 1);
    	}
    }
    
    void dfs2(int x, int fa, int now){
    	father[x] = fa;
    	if (now > cnt) cnt = now, R = x;
    	for (auto u : v[x]){
    		if (u == fa) continue;
    		dfs2(u, x, now + 1);
    	}
    }
    
    int LCA(int a, int b){
    	if (deep[a] < deep[b]) swap(a, b);
    	for (int i = 0,  delta = deep[a] - deep[b]; delta; delta >>= 1, ++i)
    		if (delta & 1) a = f[a][i];
    
    	if (a == b) return a;
    	dec(i, 19, 0) if (f[a][i] != f[b][i]){
    		a = f[a][i];
    		b = f[b][i];
    	}
    
    	return f[a][0];
    }
    
    int dis(int x, int y){
    	int z = LCA(x, y);
    	return deep[x] + deep[y] - 2 * deep[z];
    }
    
    void dfs3(int x, int fa){
    	vis[x] = 1;
    	Father[x] = fa;
    	for (auto u : v[x]){
    		if (vis[u]) continue;
    		dfs3(u, x);
    		++c[x];
    	}
    }
    
    
    int main(){
    
    	scanf("%d", &n);
    	rep(i, 1, n){
    		scanf("%d%d", &x, &y);
    		v[x].push_back(y);
    		v[y].push_back(x);
    	}
    
    	L = 0, cnt = 0;
    	dfs(1, 0, 0);
    
    	cnt = 0;
    	R = 0;
    	memset(father, 0, sizeof father);
    	dfs2(L, 0, 0);
    
    	cnt = 0;
    	x = R;
    	while (x){
    		++cnt;
    		a[cnt] = x;
    		x = father[x];
    	}
    
    	memset(vis, 0, sizeof vis);
    	rep(i, 1, cnt) vis[a[i]] = 1;
    	rep(i, 1, n)  isroot[i] = vis[i];
    	rep(i, 1, n) if (!vis[i]){
    		int now = max(dis(i, L), dis(i, R));
    		ans += 1ll * now;
    	}
    
    
    	memset(c, 0, sizeof c);
    	rep(i, 1, cnt) dfs3(a[i], 0);
    	rep(i, 1, n) if (c[i] == 0 && !isroot[i]) q.push(i);
    
    	ans = ans + 1ll * cnt * (cnt - 1) / 2;
    	printf("%lld
    ", ans);
    
    
    	while (!q.empty()){
    		x = q.front(); q.pop();
    		vis[x] = 1;
    		int al = dis(x, L), ar = dis(x, R);
    		if (al > ar) printf("%d %d %d
    ", L, x, x);
    		else printf("%d %d %d
    ", R, x, x);
    
    		int u = Father[x];
    		--c[u];
    		if (c[u] == 0 && !isroot[u]) q.push(u);
    	}
    
    	rep(i, 1, cnt - 1) printf("%d %d %d
    ", a[i], a[cnt], a[i]);
    	return 0;
    }
    
  • 相关阅读:
    JAVA学习第五十四课 — IO流(八)打印流 &amp; 序列流
    jdbc框架 commons-dbutils+google guice+servlet 实现一个例子
    java ThreadLocal 理解
    jdbc框架 commons-dbutils的使用
    Java 集合系列06之 Vector详细介绍(源码解析)和使用示例
    Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例
    Java 集合系列04之 fail-fast总结(通过ArrayList来说明fail-fast的原理、解决办法)
    Java 集合系列03之 ArrayList详细介绍(源码解析)和使用示例
    Java 集合系列02之 Collection架构
    Java 集合系列01之 总体框架
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8277345.html
Copyright © 2020-2023  润新知