Codeforces 455C Civilization:树的直径 + 并查集【合并树后直径最小】

题目链接:http://codeforces.com/problemset/problem/455/C

题意:

  给你一个森林,n个点,m条边。

  然后有t个操作。共有两种操作:

    (1)1 x:

      输出节点x所在树的直径。

    (2)2 x y:

      如果x,y不在同一棵树上的话,用一条边连接x,y所在的树,并且使得到的新树的直径尽可能小。

题解:

  首先对于初始状态,算出每一棵树的直径d[find(i)]。

  每次合并树的时候,因为要尽可能让新树直径变小,所以显然这条边要分别连接两棵树直径的“中点”。

  所以新树的直径 = max( d[x], d[y], ceil(d[x]/2)+ceil(d[y]/2)+1 )

  然后用并查集合并就好啦。

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <math.h>
  5 #include <vector>
  6 #define MAX_N 300005
  7 
  8 using namespace std;
  9 
 10 int n,m,t;
 11 int maxd;
 12 int op,ed;
 13 int d[MAX_N];
 14 int par[MAX_N];
 15 vector<int> edge[MAX_N];
 16 
 17 void init_union_find()
 18 {
 19     for(int i=1;i<=n;i++)
 20     {
 21         par[i]=i;
 22     }
 23 }
 24 
 25 int find(int x)
 26 {
 27     return par[x]==x ? x : par[x]=find(par[x]);
 28 }
 29 
 30 void unite(int x,int y)
 31 {
 32     int px=find(x);
 33     int py=find(y);
 34     if(px==py) return;
 35     par[px]=py;
 36 }
 37 
 38 bool same(int x,int y)
 39 {
 40     return find(x)==find(y);
 41 }
 42 
 43 void read()
 44 {
 45     scanf("%d%d%d",&n,&m,&t);
 46     init_union_find();
 47     int x,y;
 48     for(int i=1;i<=m;i++)
 49     {
 50         scanf("%d%d",&x,&y);
 51         edge[x].push_back(y);
 52         edge[y].push_back(x);
 53         unite(x,y);
 54     }
 55 }
 56 
 57 void dfs(int now,int p,int nd,int &v)
 58 {
 59     if(nd>maxd)
 60     {
 61         maxd=nd;
 62         v=now;
 63     }
 64     for(int i=0;i<edge[now].size();i++)
 65     {
 66         int temp=edge[now][i];
 67         if(temp!=p) dfs(temp,now,nd+1,v);
 68     }
 69 }
 70 
 71 void work()
 72 {
 73     for(int i=1;i<=n;i++)
 74     {
 75         if(find(i)==i)
 76         {
 77             maxd=-1;
 78             dfs(i,-1,0,op);
 79             maxd=-1;
 80             dfs(op,-1,0,ed);
 81             d[i]=maxd;
 82         }
 83     }
 84     int opt,x,y;
 85     while(t--)
 86     {
 87         scanf("%d",&opt);
 88         if(opt==1)
 89         {
 90             scanf("%d",&x);
 91             printf("%d
",d[find(x)]);
 92         }
 93         else
 94         {
 95             scanf("%d%d",&x,&y);
 96             if(!same(x,y))
 97             {
 98                 d[find(y)]=max(max(d[find(x)],d[find(y)]),
 99                     (int)(ceil(d[(find(x))]/2.0)+ceil(d[find(y)]/2.0)+1));
100                 unite(x,y);
101             }
102         }
103     }
104 }
105 
106 int main()
107 {
108     read();
109     work();
110 }
原文地址:https://www.cnblogs.com/Leohh/p/8206143.html