zoj3820

题意:给定一个树,找出两个点,使得其他点到最近的点的距离最小

思路:

    牡丹江站的B题。。可惜当时坑的不大对,最后也没写完。。

1、题解方法:

   基于一个结论,答案一定在直径上(证明我不会)。。

   那么,可以先求出直径,然后直接二分,二分完后o(n)判定,时间复杂度为nlogn

2、我的方法:

   赛场上写的,可惜最后由于各种原因没写完,代码难度实在比题解高多了,可惜想到了就不敢在猜想其他方法了了。。

   可以很容易证明,题目等价于对于删除某条边后求剩余两棵树直径,然后取一个最小的。。

   那么,就可以用树形dp的方法,维护每个点为子树的前三长链(以根为起始,并且来源于不同子树),还有不经过根的前两大答案,以及以其为根的子树的答案。

  先一边求完后,然后从根递推到以每个点为根成为一个树,其余为另外一棵树的答案啊。。

  这样时间复杂度为o(n)

 

code(nlog(n)):

  1 #include <bits/stdc++.h>
  2 #define M0(a, b) memset(a, 0, sizeof(int) * (b+10))
  3 using namespace std;
  4 const int maxn = 210000;
  5 int z[maxn], inz[maxn], pos[maxn], from[maxn];
  6 int L[maxn], R[maxn], cov[maxn];
  7 vector<int> e[210000];
  8 int n, m;
  9 int ans, ansx, ansy;
 10 
 11 void init(){
 12     scanf("%d", &n);    
 13     for (int i = 0; i <= n; ++i)
 14         e[i].clear();
 15     int u, v;
 16     for (int i = 1; i < n; ++i){
 17          scanf("%d%d", &u, &v);
 18          e[u].push_back(v);
 19          e[v].push_back(u);
 20     }
 21 }
 22 
 23 int pre[maxn], inq[maxn], dis[maxn];
 24 void bfs(int s, int &rt){
 25     queue<int> q;
 26     M0(inq, n), M0(dis, n), M0(pre, n);
 27     q.push(s), dis[s] = 0, inq[s] = 1;
 28     int u, v;
 29     while (!q.empty()){
 30          u = q.front();
 31          q.pop();
 32          for (int i = 0; i < (int)e[u].size(); ++i){
 33                v = e[u][i];
 34                if (!inq[v])
 35                     dis[v] = dis[u] + 1, inq[v] = 1, q.push(v), pre[v] = u;
 36          }
 37     }
 38     rt = s;
 39     for (int i = 1; i <= n; ++i)
 40         if (dis[rt] < dis[i]) rt = i;
 41 }
 42 
 43 void bfs(){
 44     queue<int> q;
 45     M0(inq, n), M0(dis, n), M0(from, n);
 46     for (int i = 1; i <= m; ++i)
 47         q.push(z[i]), inq[z[i]] = 1, from[z[i]] = i, dis[z[i]] = 0;
 48     int u, v;
 49     while (!q.empty()){
 50          u = q.front();
 51          q.pop();
 52          for (int i = 0; i < (int)e[u].size(); ++i){
 53                v = e[u][i];
 54                if (!inq[v])
 55                     dis[v] = dis[u] + 1, inq[v] = 1, q.push(v), from[v] = from[u];
 56          }
 57     }
 58 }
 59 
 60 
 61 int check(const int len, int& x, int &y){
 62     M0(L, n), M0(R, n), M0(cov, n);
 63     int d;
 64     int mleft = m + 1, mright = 0;
 65     for (int i = 1; i <= n; ++i){
 66          d = len - dis[i];
 67          if (d < 0) return 0;
 68          L[i] = max(1, from[i] - d);
 69          R[i] = min(m, from[i] + d);
 70          mleft = min(mleft, R[i]);
 71          mright = max(mright, L[i]);
 72     }
 73     for (int i = 1; i <= n; ++i)
 74        if ((L[i] <= mleft && R[i] >= mleft) || (L[i] <= mright && R[i] >= mright)) continue;
 75        else return 0;
 76     x = mleft, y = mright;
 77     if (x == y) 
 78          (y < m) ?  ++y :  --x;
 79     return 1; 
 80 }
 81 
 82 void solve(){
 83     int s, t;
 84     bfs(1, s), bfs(s, t);
 85     m = 0;
 86     M0(inz, n), M0(pos, n);
 87     while (t) z[++m] = t, pos[t] = m, t = pre[t];
 88     bfs();
 89     int l = 0, r = n, mid;
 90     int x, y;
 91     while (l <= r){
 92          mid = (l + r) >> 1;
 93          if (check(mid, x, y)) 
 94                r = mid - 1, ans = mid, ansx = z[x], ansy = z[y];
 95          else l = mid + 1;
 96     }
 97     printf("%d %d %d\n", ans, ansx, ansy);
 98 }
 99 
100 int main(){
101     int cas;
102     scanf("%d", &cas);    
103     while (cas--){
104         init();
105         solve();
106     }
107 }
View Code

code(o(n)):

  1 #include <bits/stdc++.h>
  2 #define x first
  3 #define y second
  4 #define M0(a) memset(a, 0, sizeof(int) * (n+10))
  5 #define Inf 0x3fffffff
  6 using namespace std;
  7 const int maxn = 210000;
  8 vector<int> e[maxn];
  9 pair<int, int> len[maxn][3], ans2[maxn][2], tmp[10], one(1, 0), zero(0, 0);
 10 int fa[maxn], ans1[maxn], n, ans[maxn], z[maxn];
 11 int ans_x, ans_y, ans_len;
 12 
 13 int inq[maxn], dis[maxn], pre[maxn];
 14 int pos[maxn], tot;
 15 void bfs(){
 16      M0(inq), M0(fa);
 17      queue<int> q;
 18      q.push(1), inq[1] = 1, pos[tot = 1] = 1;
 19      int u, v;
 20      while (!q.empty()){
 21           u = q.front();
 22           q.pop();
 23           for (int i = 0; i < (int)e[u].size(); ++i){
 24                v = e[u][i];
 25                if (!inq[v])
 26                     fa[v] = u, q.push(v), inq[v] = 1, pos[++tot] = v; 
 27           }
 28      }     
 29 }
 30 
 31 void gao1(const int& u){
 32      int v;
 33      for (int i = 0; i < (int)e[u].size(); ++i){
 34          v = e[u][i];
 35          if (v == fa[u]) continue;
 36          for (int j = 0; j < 3; ++j) tmp[j] = len[u][j];
 37          tmp[3] = make_pair(len[v][0].x + 1, v);
 38          sort(tmp, tmp + 4, greater<pair<int, int> >());
 39          for (int j = 0; j < 3; ++j) len[u][j] = tmp[j];
 40          if (ans1[v] > ans2[u][0].x){
 41               swap(ans2[u][1], ans2[u][0]);
 42               ans2[u][0] = make_pair(ans1[v], v);
 43          } else if (ans1[v] > ans2[u][1].x)
 44               ans2[u][1] = make_pair(ans1[v], v);
 45          ans1[u] = max(ans1[u], ans1[v]); 
 46      }
 47      ans1[u] = max(ans1[u], len[u][0].x + len[u][1].x - 1);
 48 }
 49 
 50 int ff, s[5];
 51 int ss[maxn], max_d[maxn];
 52 void gao2(const int &u){
 53      ff = fa[u];
 54      ss[u] = ss[ff];
 55      if (len[ff][0].y == u)
 56          s[0] = len[ff][1].x, s[1] = len[ff][2].x;
 57      else if (len[ff][1].y == u)
 58          s[0] = len[ff][0].x, s[1] = len[ff][2].x;
 59      else 
 60          s[0] = len[ff][0].x, s[1] = len[ff][1].x;
 61      s[2] = max_d[ff];
 62      sort(s, s + 3, greater<int>() );
 63      ss[u] = max(s[0] + s[1] - 1, ss[u]);
 64      max_d[u] = s[0] + 1;
 65      if (ans2[ff][0].y == u)
 66          ss[u] = max(ss[u], ans2[ff][1].x);
 67      else 
 68          ss[u] = max(ss[u], ans2[ff][0].x);
 69      ans[u] = max(ss[u], ans1[u]);
 70 }
 71 
 72 void pre_do(){
 73     M0(ss), M0(max_d);
 74     for (int i = 0; i <= n; ++i){
 75           len[i][0] = len[i][1] = len[i][2] = one;
 76           ans2[i][0] = ans2[i][1] = zero;
 77     }
 78 }
 79 
 80 void init(){
 81      scanf("%d", &n);
 82      pre_do();
 83      for (int i = 0; i <= n; ++i) 
 84           e[i].clear();
 85      int u, v;
 86      for (int i = 1; i < n; ++i){
 87          scanf("%d%d", &u, &v);
 88          e[u].push_back(v);
 89          e[v].push_back(u);
 90      }
 91 }
 92 
 93 void bfs(int s, int &t, const int& other){
 94     queue<int> q;
 95     M0(inq),  M0(pre);
 96     memset(dis, -1, sizeof(int) * (n+10));
 97     q.push(s), dis[s] = 0, inq[s] = 1;
 98     int u, v;
 99     while (!q.empty()){
100          u = q.front();
101          q.pop();
102          for (int i = 0; i < (int)e[u].size(); ++i){
103                v = e[u][i];
104                if (v == other) continue;
105                if (!inq[v])
106                     dis[v] = dis[u] + 1, inq[v] = 1, q.push(v), pre[v] = u;
107          }
108     }
109     t = s;
110     for (int i = 1; i <= n; ++i)
111         if (dis[t] < dis[i]) t = i;
112 }
113 
114 void solve(){
115      M0(fa), M0(ans1);
116      bfs();
117      for (int i = n; i >= 1; --i)
118           gao1(pos[i]);
119      for (int i = 2; i <= n; ++i)
120           gao2(pos[i]);
121      int rt = 2;
122      for (int i = 2; i <= n; ++i)
123           if (ans[rt] > ans[i]) rt = i;
124 //     cout << rt << endl;
125      ans_len = ans[rt] / 2;
126      int x, y;
127      bfs(rt, x, fa[rt]);
128      bfs(x, y, fa[rt]);
129      int m = 0;
130      while (y) z[m++] = y, y = pre[y];
131      ans_x = z[m/2];
132      bfs(fa[rt], x, rt);
133      bfs(x, y, rt);
134      m = 0;
135      while (y) z[m++] = y, y = pre[y];
136      ans_y = z[m/2];
137      printf("%d %d %d\n",ans_len, ans_x, ans_y);
138      
139 }
140 
141 int main(){
142     int cas;
143     scanf("%d", &cas);
144     while (cas--){
145           init();
146           solve();        
147     } 
148 }    
View Code

 

   

posted on 2014-10-15 20:09  yzcstc  阅读(167)  评论(0编辑  收藏  举报