1. 程式人生 > >Codeforces 455C Civilization:樹的直徑 + 並查集【合並樹後直徑最小】

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

font name read amp find() edge ceil -s class

題目鏈接: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 }

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