首页 > 代码库 > 2017端午欢乐赛——Day1T3(树的直径+并查集)
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 }
2017端午欢乐赛——Day1T3(树的直径+并查集)