ZOJ 3820 Building Fire Stations

Building Fire Stations

Time Limit: 5000ms

Memory Limit: 131072KB

This problem will be judged on ZJU. Original ID: 3820
64-bit integer IO format: %lld      Java class name: Main

Special Judge

Marjar University is a beautiful and peaceful place. There are N buildings and N - 1 bidirectional roads in the campus. These buildings are connected by roads in such a way that there is exactly one path between any two buildings. By coincidence, the length of each road is 1 unit.

To ensure the campus security, Edward, the headmaster of Marjar University, plans to setup two fire stations in two different buildings so that firefighters are able to arrive at the scene of the fire as soon as possible whenever fires occur. That means the longest distance between a building and its nearest fire station should be as short as possible.

As a clever and diligent student in Marjar University, you are asked to write a program to complete the plan. Please find out two proper buildings to setup the fire stations.

Input

There are multiple test cases. The first line of input contains an integer T indicating the number of test cases. For each test case:

The first line contains an integer N (2 <= N <= 200000).

For the next N - 1 lines, each line contains two integers Xi and Yi. That means there is a road connecting building Xi and building Yi (indexes are 1-based).

Output

For each test case, output three integers. The first one is the minimal longest distance between a building and its nearest fire station. The next two integers are the indexes of the two buildings selected to build the fire stations.

If there are multiple solutions, any one will be acceptable.

Sample Input

2
4
1 2
1 3
1 4
5
1 2
2 3
3 4
4 5

Sample Output

1 1 2
1 2 4

Source

The 2014 ACM-ICPC Asia Mudanjiang Regional Contest

Author

YU, Xiaoyao; ZHUANG, Junyuan

解题:树的直径+二分

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int maxn = 200010;
  4 struct arc{
  5     int to,next;
  6     arc(int x = 0,int y = -1){
  7         to = x;
  8         next = y;
  9     }
 10 }e[maxn<<1];
 11 int head[maxn],d[maxn],p[maxn],dT[maxn],dS[maxn],tot,n,S,T;
 12 bool vis[maxn];
 13 void add(int u,int v){
 14     e[tot] = arc(v,head[u]);
 15     head[u] = tot++;
 16 }
 17 queue<int>q;
 18 int bfs(int u){
 19     while(!q.empty()) q.pop();
 20     memset(d,-1,sizeof d);
 21     memset(p,-1,sizeof p);
 22     d[u] = 0;
 23     int ret = u;
 24     q.push(u);
 25     while(!q.empty()){
 26         u = q.front();
 27         q.pop();
 28         if(d[ret] < d[u]) ret = u;
 29         for(int i = head[u]; ~i; i = e[i].next){
 30             if(d[e[i].to] == -1){
 31                 d[e[i].to] = d[u] + 1;
 32                 p[e[i].to] = u;
 33                 q.push(e[i].to);
 34             }
 35         }
 36     }
 37     return ret;
 38 }
 39 int depth[maxn];
 40 int bfs2(int u){
 41     while(!q.empty()) q.pop();
 42     q.push(u);
 43     int ret = depth[u] = 0;
 44     while(!q.empty()){
 45         u = q.front();
 46         q.pop();
 47         ret = max(ret,depth[u]);
 48         for(int i = head[u]; ~i; i = e[i].next){
 49             if(vis[e[i].to]) continue;
 50             depth[e[i].to] = depth[u] + 1;
 51             q.push(e[i].to);
 52             vis[e[i].to] = true;
 53         }
 54     }
 55     return ret;
 56 }
 57 bool check(int x){
 58     int u = dT[x],v = dS[x],tmp = d[T] - (x<<1),cnt = 0;
 59     while(u != v){
 60         if(depth[u] + min(cnt,tmp - cnt) > x) return false;
 61         u = p[u];
 62         ++cnt;
 63     }
 64     return true;
 65 }
 66 int main(){
 67     int kase,u,v;
 68     scanf("%d",&kase);
 69     while(kase--){
 70         scanf("%d",&n);
 71         memset(head,-1,sizeof head);
 72         memset(vis,false,sizeof vis);
 73         int cnt = tot = 0;
 74         for(int i = 1; i < n; ++i){
 75             scanf("%d%d",&u,&v);
 76             add(u,v);
 77             add(v,u);
 78         }
 79         u = T = bfs(S = bfs(1));
 80         while(~u){
 81             dT[cnt] = u;
 82             dS[d[T] - cnt++] = u;
 83             vis[u] = true;
 84             u = p[u];
 85         }
 86         u = T;
 87         while(~u){
 88             depth[u] = bfs2(u);
 89             u = p[u];
 90         }
 91         int low = 0,high = d[T]>>1,ret = 0;
 92         while(low <= high){
 93             int mid = (low + high)>>1;
 94             if(check(mid)){
 95                 ret = mid;
 96                 u = dS[mid];
 97                 v = dT[mid];
 98                 if(u == v) u = p[u];
 99                 high = mid - 1;
100             }else low = mid + 1;
101         }
102         printf("%d %d %d\n",ret,u,v);
103     }
104     return 0;
105 }

时间: 2024-09-30 04:45:55

ZOJ 3820 Building Fire Stations的相关文章

zoj 3820 Building Fire Stations(二分法+bfs)

题目链接:zoj 3820 Building Fire Stations 题目大意:给定一棵树.选取两个建立加油站,问说全部点距离加油站距离的最大值的最小值是多少,而且随意输出一种建立加油站的方式. 解题思路:二分距离推断,推断函数的复杂度是o(n),这种复杂度应该是o(nlogn).即使常数系数偏大,可是竟然跑了4.5s,也是醉了. 推断函数里面做了3次bfs,可是每次bfs节点最多遍历1次,首先任取一点做根建立一个树,找到深度最大的节点.以向上移动L(推断的ans)位置处的节点建立加油站,并

zoj 3820 Building Fire Stations(二分+bfs)

题目链接:zoj 3820 Building Fire Stations 题目大意:给定一棵树,选取两个建立加油站,问说所有点距离加油站距离的最大值的最小值是多少,并且任意输出一种建立加油站的方式. 解题思路:二分距离判断,判断函数的复杂度是o(n),这样的复杂度应该是o(nlogn),即使常数系数偏大,但是居然跑了4.5s,也是醉了. 判断函数里面做了3次bfs,但是每次bfs节点最多遍历1次,首先任取一点做根建立一个树,找到深度最大的节点,以向上移动L(判断的ans)位置处的节点建立加油站,

zoj 3820 Building Fire Stations 树的中心

Building Fire Stations Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3820 Description Marjar University is a beautiful and peaceful place. There are N buildings and N - 1 bidirectional roads

zoj 3820 Building Fire Stations (二分+树的直径)

Building Fire Stations Time Limit: 5 Seconds      Memory Limit: 131072 KB      Special Judge Marjar University is a beautiful and peaceful place. There are N buildings and N - 1 bidirectional roads in the campus. These buildings are connected by road

zoj 3820 Building Fire Stations(树上乱搞)

做同步赛的时候想偏了,状态总是时好时坏.这状态去区域赛果断得GG了. 题目大意:给一棵树.让求出树上两个点,使得别的点到两个点较近的点的距离最大值最小. 赛后用O(n)的算法搞了搞,事实上这道题不算难.逗逼的没A.. 事实上这两个点一定是树直径上的两个点,假设能想到这个就非常好搞了,仅仅须要求出树的直径,然后从中间位置把树拆成两颗子树,然后分别求出子树的中心就好了. 证明例如以下,假如我们已经求出树上的两个点u, v满足条件.那么,我们从u, v中间把树拆开肯定是最优的.这个非常easy想到.

ZOJ 3820 Building Fire Stations 贪心+树的直径

不知道为什么是对的,但是举不出反例,比赛的时候队友提出找树的直径,不过我没敢写,真是可惜. 具体做法就是先找到原树的直径,然后删去最中间的一条边,变为两个子树,分别球两颗子树的直径中点,便是答案了. #include <cstdio> #include <cstring> #include <algorithm> #include <queue> #include <stack> #include <map> #include <

ZOJ 3820 Building Fire Stations 求中点+树的直径+BFS

题意:给一棵树,要求找出两个点,使得所有点到这两个点中距离与自己较近的一个点的距离的最大值(所有点的结果取最大的值,即最远距离)最小. 意思应该都能明白. 解法:考虑将这棵树摆直如下: 那么我们可以把最中间的那条直径边删掉,然后在分成的两颗子树内求一个直径中心点,那么这两个点就可以作为答案. 反正当时就觉得这样是正确的, 但是不能证明. 于是,几个bfs就可以搞定了. 当时写TLE了,原因是存要删的边我用了map<pair<int,int>,int>, 后来改掉就不T了,map这种

ZOJ 3820:Building Fire Stations(树的直径 Grade C)

题意: n个点的树,边长全为1,求找出两个点,使得树上离这两个点距离最远的那个点,到这两个点(中某个点就行)的距离最小. 思路: 求树直径,找中点,删除中间那条边(如果直径上点数为奇数,则删任何一侧都可),分成两个子树,再求中心,即为答案. 代码: //14:12 #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 200100 struct G

ZOJ Problem Set - 3820 Building Fire Stations 【树的直径 + 操作 】

题目:problemId=5374" target="_blank">ZOJ Problem Set - 3820 Building Fire Stations 题意:给出n个点,n-1条边的一棵树.然后要在两个点上建立两个消防站.让全部点的到消防站最大距离的点的这个距离最小. 分析:首先先求这个树的直径.然后在树的直径的中点处把树分成两棵树.然后在把两棵树分别取中点的最大值就是ans值. 这个题目数据有点水了感觉... AC代码: #include <cstdi