Codeforces 455C Civilization:樹的直徑 + 並查集【合併樹後直徑最小】

Leohh發表於2018-01-05

題目連結: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\n",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 }

 

相關文章