题目链接:
http://codeforces.com/problemset/problem/455/C
题意:
n个点,m条边的森林,q次操作。每次操作:1、询问x所在树的直径 2、合并x和y所在的树,使得合并后的直径最小
(1 ≤ n ≤ 3e5; 0 ≤ m < n; 1 ≤ q ≤ 3e5)
思路:
一棵树的最长路径是树的直径,可以用并查集维护每棵树的直径,然后合并两棵树的时候要使新树的最长路径最小,
考虑怎么使合并的时候两颗树的直径最小,加的边一定连接两棵树的直径的中点,用并查集维护,合并后的树的直径是
max(ans[p1],max(ans[p2],(ans[p1]+1)/2+(ans[p2]+1)/2+1));
我找树的直径是用spfa,多棵树的时候,对全部的点都初始化了,TLE。 所以把每颗树单独拿出来,计算答案。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define MS(a) memset(a,0,sizeof(a)) 5 #define MP make_pair 6 #define PB push_back 7 const int INF = 0x3f3f3f3f; 8 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL; 9 inline ll read(){ 10 ll x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 13 return x*f; 14 } 15 ////////////////////////////////////////////////////////////////////////// 16 const int maxn = 3e5+10; 17 18 int n,m,Q; 19 int ans[maxn],fa[maxn]; 20 int inq[maxn],d[maxn]; 21 vector<int> g[maxn],gg[maxn]; 22 queue<int> q; 23 int vis[maxn]; 24 25 int find(int x){ 26 return fa[x]==x ? x : fa[x]=find(fa[x]); 27 } 28 29 int main(){ 30 MS(ans); 31 cin >> n >> m >> Q; 32 for(int i=0; i<=n; i++) g[i].clear(),gg[i].clear(); 33 for(int i=0; i<=n; i++) fa[i] = i, vis[i]=0; 34 for(int i=0; i<m; i++){ 35 int u,v; scanf("%d%d",&u,&v); 36 g[u].push_back(v); 37 g[v].push_back(u); 38 int p1 = find(u), p2 = find(v); 39 if(p1 == p2) continue; 40 else fa[p1] = p2; 41 } 42 for(int i=1; i<=n; i++){ 43 int p = find(i); 44 gg[p].push_back(i); 45 } 46 for(int u=1; u<=n; u++){ 47 if(fa[u]!=u) continue; 48 inq[u] = 0, d[u] = INF; 49 for(int i=0; i<(int)gg[u].size(); i++) { 50 int v = gg[u][i]; 51 inq[v]=0; d[v] = INF; 52 } 53 q.push(u); 54 inq[u]=1; d[u]=0; 55 while(!q.empty()){ 56 int now = q.front(); q.pop(); 57 for(int i=0; i<(int)g[now].size(); i++){ 58 int v = g[now][i]; 59 if(d[v] > d[now]+1){ 60 d[v] = d[now]+1; 61 if(inq[v]) continue; 62 inq[v] = 1; 63 q.push(v); 64 } 65 } 66 } 67 int tmp = d[u], k; 68 for(int i=0; i<(int)gg[u].size(); i++){ 69 int v = gg[u][i]; 70 if(d[v]==INF) continue; 71 if(tmp < d[v]) tmp=d[v], k = v; 72 } 73 74 inq[u] = 0, d[u] = INF; 75 for(int i=0; i<(int)gg[u].size(); i++) { 76 int v = gg[u][i]; 77 inq[v]=0; d[v] = INF; 78 } 79 q.push(k); 80 inq[k]=1; d[k]=0; 81 while(!q.empty()){ 82 int now = q.front(); q.pop(); 83 for(int i=0; i<(int)g[now].size(); i++){ 84 int v = g[now][i]; 85 if(d[v] > d[now]+1){ 86 d[v] = d[now]+1; 87 if(inq[v]) continue; 88 inq[v] = 1; 89 q.push(v); 90 } 91 } 92 } 93 94 tmp = d[k]; 95 if(d[u]!=INF) tmp = max(tmp,d[u]); 96 for(int i=0; i<(int)gg[u].size(); i++){ 97 int v = gg[u][i]; 98 if(d[v]==INF) continue; 99 tmp = max(tmp,d[v]); 100 } 101 ans[u] = tmp; 102 // cout << u << " " << tmp << endl; 103 } 104 105 for(int i=0; i<Q; i++){ 106 int op = read(); 107 if(op == 1){ 108 int x = read(); 109 printf("%d ",ans[find(x)]); 110 }else{ 111 int x,y; scanf("%d%d",&x,&y); 112 int p1 = find(x), p2 = find(y); 113 // cout << p1 << " " << p2 << " == "; 114 if(p1 != p2){ 115 fa[p1] = p2; 116 // cout << ans[p1] << " " << ans[p2] << " ** "; 117 ans[p2] = max(ans[p1],max(ans[p2],(ans[p1]+1)/2+(ans[p2]+1)/2+1)); 118 } 119 } 120 } 121 122 123 return 0; 124 }