CF455C Civilization (并查集)

CF456E

Codeforces Round #260 (Div. 1) C

Codeforces Round #260 (Div. 2) E

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

C. Civilization
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Andrew plays a game called "Civilization". Dima helps him.

The game has n cities and m bidirectional roads. The cities are numbered from 1 to n. Between any pair of cities there either is a single (unique) path, or there is no path at all. A path is such a sequence of distinct cities v1, v2, ..., vk, that there is a road between any contiguous cities vi and vi + 1 (1 ≤ i < k). The length of the described path equals to (k - 1). We assume that two cities lie in the same region if and only if, there is a path connecting these two cities.

During the game events of two types take place:

  1. Andrew asks Dima about the length of the longest path in the region where city x lies.
  2. Andrew asks Dima to merge the region where city x lies with the region where city y lies. If the cities lie in the same region, then no merging is needed. Otherwise, you need to merge the regions as follows: choose a city from the first region, a city from the second region and connect them by a road so as to minimize the length of the longest path in the resulting region. If there are multiple ways to do so, you are allowed to choose any of them.

Dima finds it hard to execute Andrew's queries, so he asks you to help him. Help Dima.

Input

The first line contains three integers n, m, q (1 ≤ n ≤ 3·105; 0 ≤ m < n; 1 ≤ q ≤ 3·105) — the number of cities, the number of the roads we already have and the number of queries, correspondingly.

Each of the following m lines contains two integers, ai and bi (ai ≠ bi; 1 ≤ ai, bi ≤ n). These numbers represent the road between cities ai and bi. There can be at most one road between two cities.

Each of the following q lines contains one of the two events in the following format:

  • 1 xi. It is the request Andrew gives to Dima to find the length of the maximum path in the region that contains city xi (1 ≤ xi ≤ n).
  • 2 xi yi. It is the request Andrew gives to Dima to merge the region that contains city xi and the region that contains city yi (1 ≤ xi, yi ≤ n). Note, that xi can be equal to yi.
Output

For each event of the first type print the answer on a separate line.

Sample test(s)
Input
6 0 6
2 1 2
2 3 4
2 5 6
2 3 2
2 5 3
1 1
Output
4

题意:

给出N个点,M条边,组成无环图(树),给出Q个操作,操作有两种:

1 x  ,输出x所在的联通块的最长路;

2 x y  ,若x和y在同一联通块,则不操作;若不在同一联通块,则选择这两个联通块的各一个城市连一条边,使新的联通块的最长路最短,若有多种选择则随便选。

 

题解:

并查集+树的直径

我是看http://blog.csdn.net/keshuai19940722/article/details/38455333的碉炸题解学会的,简直碉炸。

这题认真看其实不难,只是我当时太怂了没看……

首先我们根据初始的边用求树的直径的方法求出每块的最长路,方法就是两遍dfs,第一遍找距离起点最远的点x,这个x肯定是最长路的一端,然后我们从x再dfs一遍,得到最长路md[x],顺便把整个块的father设为x。

然后操作一就很容易实现,主要是操作二。操作二其实不用真的去连那条边,只要心中有那条边就行,因为连起来后其实主要我们也只看每个块最长路md[x],其他信息都不用管。设两个块的祖先为fx,fy,设fx的最长路不小于fy的最长路,则我们要把fy的father设为fx,然后更新md[fx]。这个厉害了,我们只要一个超碉的式子就能得到新的md[fx]

    md[fx]=max(md[fx], (md[fx]+1)/2 + (md[fy]+1)/2 + 1 );

就是把[x块的最长路的中间点]连接[y块的最长路的中间点],得到的新路的长度是(x块最长路的一半)加上(y块最长路的一半)加上1。

怪不得天梯第一的tourist大神能十多分钟做出来,果然水,不要不服!只是我们比题还水,一下看不出来这样做…

代码:

  1 //#pragma comment(linker, "/STACK:102400000,102400000")
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<queue>
 12 using namespace std;
 13 #define ll long long
 14 #define usint unsigned int
 15 #define mz(array) memset(array, 0, sizeof(array))
 16 #define minf(array) memset(array, 0x3f, sizeof(array))
 17 #define REP(i,n) for(i=0;i<(n);i++)
 18 #define FOR(i,x,n) for(i=(x);i<=(n);i++)
 19 #define RD(x) scanf("%d",&x)
 20 #define RD2(x,y) scanf("%d%d",&x,&y)
 21 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
 22 #define WN(x) printf("%d\n",x);
 23 #define RE  freopen("D.in","r",stdin)
 24 #define WE  freopen("1biao.out","w",stdout)
 25 
 26 const int maxn=300011;
 27 
 28 struct EDGE{
 29     int v,next;
 30 }e[maxn<<1];
 31 int head[maxn],en;
 32 int f[maxn],md[maxn];
 33 int n,m,q;
 34 int maxd,maxi,thefather;
 35 void add(int x,int y){
 36     e[en].v=y;
 37     e[en].next=head[x];
 38     head[x]=en++;
 39 }
 40 
 41 int getfather(int x){
 42     return f[x]==x ? x:f[x]=getfather(f[x]);
 43 }
 44 
 45 void link(int x,int y){
 46     int fx,fy;
 47     fx=getfather(x);
 48     fy=getfather(y);
 49     if(fx==fy)return;
 50     if(md[fx]<md[fy])swap(fx,fy);
 51     md[fx]=max(md[fx], (md[fx]+1)/2 + (md[fy]+1)/2 + 1 );
 52     f[fy]=fx;
 53 }
 54 
 55 void dfs(int x,int prex,int step){
 56     f[x]=thefather;
 57     if(step>maxd){
 58         maxd=step;
 59         maxi=x;
 60     }
 61     for(int i=head[x]; i!=-1; i=e[i].next)
 62         if(e[i].v!=prex) dfs(e[i].v,x,step+1);
 63 }
 64 
 65 void check(int a[],int n){
 66     for(int i=0;i<n;i++)
 67         printf("%d ",a[i]);
 68     puts("");
 69 }
 70 
 71 int main()
 72 {
 73     int i,x,y,z;
 74     while(scanf("%d%d%d",&n,&m,&q)!=EOF){
 75         memset(head,-1,sizeof(head));
 76         en=0;
 77         REP(i,m) {
 78             scanf("%d%d",&x,&y);
 79             add(x,y);
 80             add(y,x);
 81         }
 82         for(i=1; i<=n ;i++)
 83             f[i]=i;
 84         for(i=1; i<=n; i++)
 85             if(f[i]==i){
 86                 maxd=-1;
 87                 thefather=i;
 88                 dfs(i,-1,0);
 89                 maxd=-1;
 90                 thefather=maxi;
 91                 dfs(thefather,-1,0);
 92                 md[thefather]=maxd;
 93             }
 94         REP(i,q){
 95             scanf("%d",&z);
 96             if(z==1){
 97                 scanf("%d",&x);
 98                 printf("%d\n",md[getfather(x)]);
 99             }else{
100                 scanf("%d%d",&x,&y);
101                 link(x,y);
102 //                check(md,n+1);
103 //                check(f,n+1);
104             }
105         }
106     }
107     return 0;
108 }
View Code

 

posted @ 2014-08-09 14:55  带鱼Yuiffy  阅读(573)  评论(0编辑  收藏  举报