2017端午歡樂賽——Day1T3(樹的直徑+並查集)
//前些天的和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(樹的直徑+並查集)