1. 程式人生 > >2017端午歡樂賽——Day1T3(樹的直徑+並查集)

2017端午歡樂賽——Day1T3(樹的直徑+並查集)

模擬 -s alt algorithm const image scanf () ear

//前些天的和jdfz的神犇們聯考的模擬賽。那天上午大概是沒睡醒吧,考場上忘了寫輸出-1的情況,白丟了25分真是**。

題目描述

小C所在的城市有 n 個供電站,m條電線。相連的供電站會形成一個供電群,那麽為了節省材料,供電群是一棵樹的形式,也即城市是一個森林的形式(樹V個點,V-1條邊的無向連通圖,森林:若幹棵樹)。每個供電群中不需要所有供電站都工作,最少只需要一個工作,其余的就都會通過電線收到電,從而完成自己的供電任務。當然,這樣會產生延遲。定義兩個供電站的延遲為它們之間的電線數量,供電群的最大延遲為其中兩兩供電站的延遲中最大的那一個,即樹的直徑。小C現有q個操作,每個操作形如“a b”,表示想要將a所在的供電群中任意一個供電站和b所在的供電群中任意一個供電站之間連一條電線,使得它們成為同一個供電群,並且使這個供電群的最大延遲最小。請輸出這個最小的最大延遲。如果 a和 b已經在同一個供電群中,則輸出-1,此時不需要進行連線操作。

————————————————————————————————————————————————————————————

輸入

第一行兩個整數 n,m (m<n)
下面 m 行,每行兩個整數 a,b,代表 a,b 間有一條無向邊
  下面一行一個整數 q
  下面 q 行,每行兩個整數 a,b,代表操作

————————————————————————————————————————————————————————————

輸出

  輸出 q 行,第 i 行一個整數代表操作 i 的答案。

————————————————————————————————————————————————————————————

樣例輸入

  10 7

  1 2

  1 3

  3 4

  3 5

  6 7

  8 9

  8 10

  2

  1 6

  2 8

————————————————————————————————————————————————————————————

樣例輸出

  4

  4

————————————————————————————————————————————————————————————

樣例解釋與數據範圍

技術分享

技術分享

技術分享

—————————————————————————————————————————————————————————————————

顯然樹的直徑+並查集

而連接兩棵樹,若使其連完以後直徑最小,則必須連兩棵樹的直徑的中點。

合並後的直徑 max(gg[v],max(gg[u],(gg[v]+1)/2+(gg[u]+1)/2+1));

可以稍微預處理出樹的直徑。

記得判斷a和b在同一個供電群的情況。

————————————————————————————————————————————————————————————

技術分享
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 #include<cstring>
  6 const int maxn=1000009; 
  7 using namespace std;
  8 
  9 int n,m,QAQ;//n個供電站,m條電線,Q個操作 
 10 int head[maxn],nxt[maxn<<1],edge[maxn<<1];
 11 int k,flag;
 12 int q[maxn],visited[maxn];
 13 int fa[maxn];
 14 int gg[maxn]; 
 15 
 16 void add(int u,int v)
 17 {
 18     edge[k]=v;
 19     nxt[k]=head[u];
 20     head[u]=k++;
 21 }
 22 
 23 void bfs(int u,int fl)
 24 {
 25     int i,rear=0,frt=0;
 26     q[rear++]=u;
 27     visited[u]=1;
 28     while(frt<rear)
 29     {
 30         int h=q[frt++];
 31         for(i=head[h];i!=-1;i=nxt[i])
 32         {
 33             if(!visited[edge[i]])
 34             {
 35                 visited[edge[i]]=visited[h]+1;
 36                 q[rear++]=edge[i];
 37             }
 38         }
 39     }
 40 
 41     if(!fl){for(i=rear-1;i>=0;i--) visited[q[i]]=0;}
 42     flag=q[rear-1];
 43     
 44 }
 45 
 46 int find(int x)
 47 {
 48     if(fa[x]==x)return x;
 49     else return fa[x]=find(fa[x]);
 50 }
 51 
 52 int maxx(int x,int y)
 53 {
 54     return x>y?x:y;
 55 }
 56 
 57 int main()
 58 {
 59     freopen("connect.in","r",stdin);
 60     freopen("connect.out","w",stdout);
 61     int u,v;
 62     while(scanf("%d%d",&n,&m)!=EOF)
 63     {
 64         memset(head,-1,sizeof(head));
 65         memset(gg,0,sizeof(gg));
 66         memset(visited,0,sizeof(visited));
 67         k=0;
 68 
 69         for(int i=1;i<=n;i++)
 70             fa[i]=i;
 71 
 72         for(int i=0;i<m;i++)
 73         {
 74             scanf("%d%d",&u,&v);
 75             add(u,v);
 76             add(v,u);
 77             u=find(u);
 78             v=find(v);
 79             if(u!=v) fa[u]=v;
 80         }
 81 
 82         for(int i=1;i<=n;i++)
 83             fa[i]=find(i);
 84         for(int i=1;i<=n;i++)
 85         {
 86             if(!visited[i])
 87             {
 88                 bfs(i,0);
 89                 bfs(flag,1);
 90                 gg[fa[i]]=visited[flag]-1;
 91             }
 92         }
 93         cin>>QAQ; 
 94         for(int i=0;i<QAQ;i++)
 95         {
 96             scanf("%d%d",&u,&v);
 97             u=find(u);
 98             v=find(v);
 99             if(u!=v)
100             { 
101                 fa[u]=v;
102                 int mm=maxx(gg[u],gg[v]);
103                 gg[v]=maxx((gg[v]+1)/2+(gg[u]+1)/2+1,mm);//除以2向上取整 
104                 gg[u]=0;
105             } 
106             if(gg[u]==gg[v]) //同一供電群 
107             {
108                 cout<<"-1"<<endl;
109                 continue;
110             }
111             printf("%d\n",gg[find(u)]);
112         }
113     }
114     fclose(stdin);
115     fclose(stdout);
116     return 0;
117 }
View Code

2017端午歡樂賽——Day1T3(樹的直徑+並查集)