• 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 }
  • 相关阅读:
    739. Daily Temperatures
    535. Encode and Decode TinyURL
    811. Subdomain Visit Count
    706. Design HashMap
    C++-static作用(转)
    大学四年应当如何渡过(转)
    计算机导论第八章-总结
    计算机导论第四章习题
    计算机导论-第一章习题
    20世纪最伟大的十大算法
  • 原文地址:https://www.cnblogs.com/Leohh/p/8206143.html
Copyright © 2020-2023  润新知