Codeforces Round #615 (Div. 3) F 运行最快的做法!!


一开始输出是cout,发现就第二了,改printf就直接第一快了。我说下这题我的做法是什么。题目就是给你一棵树,叫你给出三个点,这三个点相连的简单路径的边数最多。样例的图解释的很清楚是什么意思了。
怎么做呢?我一开始首先考虑两个点相连的情况,两个点的情况下什么时候会是拥有最长的边数?很明显就是大家都知道的两个点是树直径的端点时候,树直径大家都会,随便找一点bfs/dfs出最远的一个点,这个点就是树直径的其中一个端点,然后普通树直径的另一个端点就是从这个已知端点出发,再跑一次,跑出第二个端点。
两个点就确定了,接下来我们要考虑要怎么得出第三个点?由于我们是跑出来了树直径,在直径上的每个点(除了端点),都是会在延伸出其他的枝叶(连着其他的边,但是这个边不在直径里面),很明显我们要的第三个点,就是在树直径上的点延伸出去的最远的那个点去作为第三个点。

这个例子的绿线就是树直径,黄色的点就是题目要求的三个点。
那么如何跑出这个第三个点呢?理论上,我们去得到树的直径上有哪些点/边,去dfs跑另外的边,这样是可行的。
但是我的做法就是与求第二个点的坐标一起跑出来。
我们思考下,当我们求出树直径的第一个点point1的时候,是不是就是可以当做以这个点为根的树,那么树直径另一个端点在哪里呢?在以point1为根的树的深度最深的任意一个点。只要我们求出深度最深的点,也就是知道point2,树直径的第二个点,然后我们在这遍求深度的dfs中,可以维护一些其他东西让我们能得出第三个点

  1. father[i], 记录的是i点的父亲是谁
  2. maxdep[i],以i为根的子树中, 深度最远的节点的深度是多少
  3. maxdeppoint[i] 以i为根的子树中,深度最远的节点是谁?
  4. deep_[i] , 节点i的深度
    很明显2,3我们只要在dfs的时候去判断一下就好了,这就类似dp?
    	for (int i = head[now]; i; i = xian[i].next) {
    		int to = xian[i].to;
    		if (to == fa)continue;
    		dfs(to, now);
    		if (maxdep[now] < maxdep[to]) {
    			maxdep[now] = max(maxdep[now], maxdep[to]);
    			maxdeppoint[now] = maxdeppoint[to];
    		}
    	}

接下来解释下怎么跑出第三个点,首先我们根据深度就可以知道point2,就是树直径另一个端点。然后我们根据father【i】就可以吧树直径上所有点都标记上,写个while。
然后我们去遍历所有点,只要这个点不是在树直径上,并且这个点的父亲是在树直径上,(为什么点的父亲需要在直径上?因为如果点的父亲不在直径上,那么这个点的父亲所能提供的贡献肯定比当前点大)那么就去算出这条枝干能提供的贡献(该点位根的最远深度减去父亲的深度),找出最大贡献的枝干,根据我们的maxdeppoint就可知道第三个点的下标。

下面是代码(46ms)

        #include<iostream>
        #include<cstdio>
        #include<stack>
        #include<algorithm>
        #include<cstring>
        #include<queue>
        #include<vector>
        #include<time.h>
        #include<string>
        #include<cmath>
        #include <ctime>
        #include<bitset>
        #include <cctype>
        #define low_bit(x) ((x)&(-(x)))
        #define debug cout<<"*********degug**********";
        #define index index_
        #define ll long long
        #define RE register
        #define yn yn_
        using namespace std;
        const long long max_ = 3e5 + 7;
        const int mod = 1e9 + 7;
        const int inf = 1e9;
        const long long INF = 1e18;
        int read() {
        	int s = 0, f = 1;
        	char ch = getchar();
        	while (ch<'0' || ch>'9') {
        		if (ch == '-')
        			f = -1;
        		ch = getchar();
        	}
        	while (ch >= '0'&&ch <= '9') {
        		s = s * 10 + ch - '0';
        		ch = getchar();
        	}
        	return s * f;
        }
        inline int min(int a, int b) {
        	return a < b ? a : b;
        }
        inline int max(int a, int b) {
        	return a > b ? a : b;
        }
        int head[max_], xiann = 2,father[max_],deep_[max_],n,vis[max_],point1,maxdep[max_],md = 0, point2,aim[max_], point3, maxdeppoint[max_];
        struct {
        	int next, to;
        }xian[max_ * 2];
        inline void add(int a, int b) {
        	xian[xiann].next = head[a];
        	xian[xiann].to = b;
        	head[a] = xiann;
        	xiann++;
        }
        queue<int>que;
        void bfs() {
        	que.push(1); 
        	while (!que.empty()){
        		int tou = que.front(); que.pop();
        		if (vis[tou])continue;
        		vis[tou] = 1;
        		point1 = tou;
        		for (int i = head[tou]; i; i = xian[i].next) {
        			int to = xian[i].to;
        			if (vis[to])continue;
        			que.push(to);
        		}
        	}
        }
        void dfs(int now, int fa) {
        	deep_[now] = deep_[fa] + 1;
        	father[now] = fa;
        	md = max(md, deep_[now]);
        	maxdeppoint[now] = now;
        	maxdep[now] = deep_[now];
        	for (int i = head[now]; i; i = xian[i].next) {
        		int to = xian[i].to;
        		if (to == fa)continue;
        		dfs(to, now);
        		if (maxdep[now] < maxdep[to]) {
        			maxdep[now] = max(maxdep[now], maxdep[to]);
        			maxdeppoint[now] = maxdeppoint[to];
        		}
        	}
        }
        int main() {
        	 n = read();
        	 for (int i = 2; i <= n; i++) {
        		 int a = read(), b = read();
        		 add(a, b); add(b, a);
        	 }
        	 bfs();
        	 deep_[0] = -1;
        	 dfs(point1, 0);
        	 for (int i = 1; i <= n; i++) {
        		 if (deep_[i] == md) {
        			 point2 = i; break;
        		 }
        	 }
        	 aim[point2] = 1; aim[point1] = 1;
        	 int now = point2;
        	 while (now != point1){
        		 now = father[now];
        		 aim[now] = 1;
        	 }
        	 for (int i = 1; i <= n; i++) {
        		 if (i != point2 && i != point1) {
        			 point3 = i; break;
        		 }
        	 }
        	 int ans = md,vv = 0;
        	 for (int i = 1; i <= n; i++) {
        		 if (!aim[i] && aim[father[i]]) {
        			 if (vv < maxdep[i] - deep_[father[i]]) {
        				 vv = maxdep[i] - deep_[father[i]];
        				 point3 = maxdeppoint[i];
        			 }
        			 
        		 }
        	 }
    printf("%d\n%d %d %d",ans + vv,point1 ,point2,point3);
        	 //cout << ans + vv<<endl<<point1 <<" "<<point2<<" "<<point3;
        	return 0;
        }
全部评论

相关推荐

孤寡孤寡的牛牛很热情:为什么我2本9硕投了很多,都是简历或者挂,难道那个恶心人的测评真的得认真做吗
点赞 评论 收藏
分享
藏剑天涯:全要了 领4份工资
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务