做同步赛的时候想偏了,状态总是时好时坏,这状态去区域赛果断得GG了。
题目大意:给一棵树,让求出树上两个点,使得别的点到两个点较近的点的距离最大值最小。
赛后用O(n)的算法搞了搞,其实这道题不算难。逗逼的没A。。
其实这两个点一定是树直径上的两个点,如果能想到这个就很好搞了,只需要求出树的直径,然后从中间位置把树拆成两颗子树,然后分别求出子树的中心就好了。
证明如下,假如我们已经求出树上的两个点u, v满足条件。那么,我们从u, v中间把树拆开肯定是最优的,这个很容易想到。然后,对于u点,肯定在原树的直径上,因为假如u点没有在直径上的话,u点一定是在子树的一个分支上,而且到树直径端点的距离小于等于u到分支端点的距离,这样的话分支定可以取代原来直径上的一个端点而成为直径,u在直径上,与假设矛盾。所以u一定在直径上,同理v也一定在直径上。然后就搞出来了==
//#pragma comment(linker, "/STACK:1024000000,1024000000") #include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<string> #include<queue> #include<cmath> #include<stack> #include<set> #include<map> #define LL long long #define INF 0x3f3f3f3f #define CLR(a, b) memset(a, b, sizeof(a)) using namespace std; const int maxn = 202000; vector<int> G[maxn]; vector<int> d; bool vis[maxn]; int fa[maxn]; int bfs1(int s) { int ret = -1; CLR(vis, false); vis[s] = true; queue<int> q; fa[s] = -1; q.push(s); vis[s] = true; while(!q.empty()) { int u = q.front(); q.pop(); ret = u; for(int i = 0; i < G[u].size(); i ++) { int v = G[u][i]; if(vis[v]) continue; vis[v] = true; q.push(v); fa[v] = u; } } return ret; } int deg[maxn]; int cnt[maxn], n; pair<int, int> bfs2(int u, int fa) { queue<int> q; CLR(vis, false); q.push(u); vis[u] = true; if(deg[u] == 0) return make_pair(u, 0); while(!q.empty()) { int u = q.front(); q.pop(); for(int i = 0; i < G[u].size(); i ++) { int v = G[u][i]; if(vis[v] || v == fa) continue; q.push(v); vis[v] = true; } } queue<pair<int, int> > q2; for(int i = 1; i <= n; i ++) if(vis[i]) { if(deg[i] == 1) q2.push(make_pair(i, 0)); else vis[i] = false; } pair<int, int> ret; CLR(cnt, 0); while(!q2.empty()) { pair<int, int> u = q2.front(); q2.pop(); ret = u; cnt[u.second] ++; for(int i = 0; i < G[u.first].size(); i ++) { int v = G[u.first][i], len = u.second + 1; if(v == fa || deg[v] == 1) continue; deg[v] --; if(deg[v] == 1) q2.push(make_pair(v, len)); } } if(cnt[ret.second] > 1) ret.second ++; return ret; } inline int get_int(){ int ret=0;char c; while(!isdigit(c=getchar())); do {ret = (ret<<3)+(ret<<1)+c-'0'; }while(isdigit(c=getchar())); return ret; } int main() { int T; scanf("%d", &T); while(T --) { scanf("%d", &n); for(int i = 1; i <= n; i ++) G[i].clear(), deg[i] = 0; for(int i = 1; i < n; i ++) { int u = get_int(), v = get_int(); G[u].push_back(v); G[v].push_back(u); deg[u] ++; deg[v] ++; } d.clear(); int s = bfs1(bfs1(1)); for(int i = s; ~i; i = fa[i]) { d.push_back(i); } int u = d[d.size() / 2], v = d[d.size() / 2 - 1]; deg[u] --; deg[v] --; pair<int, int> r1 = bfs2(u, v), r2 = bfs2(v, u); int ans = max(r1.second, r2.second); printf("%d %d %d\n", ans, r1.first, r2.first); } } /* 222 4 1 2 1 3 1 4 5 1 2 2 3 3 4 4 5 11 1 2 2 3 3 4 4 5 5 6 6 7 7 8 6 9 9 10 10 11 */
zoj 3820 Building Fire Stations(树上乱搞)
原文地址:http://blog.csdn.net/ok_again/article/details/40043197