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 secondmemory limit per test
256 megabytesinput
standard inputoutput
standard outputAndrew 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:
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:
Output
For each event of the first type print the answer on a separate line. Sample test(s)
Input
6 0 6 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 }