Codeforces Round #260 (Div. 1)C. Civilization 并查集+树的直径

题目链接:

http://codeforces.com/problemset/problem/455/C

题意:

n个点,m条边的森林,q次操作。每次操作:1、询问x所在树的直径 2、合并x和y所在的树,使得合并后的直径最小
(1 ≤ n ≤ 3e5; 0 ≤ m < n1 ≤ 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\n",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 << "  ==\n";
114             if(p1 != p2){
115                 fa[p1] = p2;
116 //                cout << ans[p1] << " " << ans[p2] << " **\n";
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 }

 

posted @ 2017-05-24 13:12  _yxg123  阅读(182)  评论(0编辑  收藏  举报