题解 P2195 【HXY造公园】
天哪这道题竟然只有一篇题解!
emm,首先读题看完两个操作就已经有很明确的思路了,显然是并查集+树的直径 一波解决。
并查集不多说了,如果不了解的可以看这里.
树的直径的思路很朴实,就是两边DFS(BFS也OK)。具体先随便找一个节点,然后搜一遍,找到最远的,然后再搜一遍,这样合在一起就一定是最长的了。
不过呢这道题还是注意一下求直径的公式,具体如下:
$D_new=max(D_u,D_v,[D_u/2]+[D_v/2]+1)$
那个方括号指的是取整(没找到在哪里打出来)。
en除此之外好像没什么好说的。。。
AC代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 using namespace std; 6 7 const int maxn=300300; 8 9 int n,m,q,max_i,max_v; 10 int f[maxn],len[maxn],sz[maxn]; 11 bool used[maxn]; 12 vector<int>g[maxn]; 13 14 void dfs(int val,int depth,int pos){ 15 if(depth>max_i){ 16 max_i=depth; 17 max_v=val; 18 } 19 for(int i=0;i<g[val].size();i++){ 20 if(g[val][i]!=pos)dfs(g[val][i],depth+1,val); 21 } 22 } 23 24 int calc(int val){ 25 max_i=-1; 26 dfs(val,0,-1); 27 max_i=-1; 28 dfs(max_v,0,-1); 29 return max_i; 30 } 31 32 int find(int x){ 33 if(x==f[x])return x; 34 return f[x]=find(f[x]); 35 } 36 37 void merge(int x,int y){ 38 x=find(x),y=find(y); 39 if(sz[x]>sz[y])swap(x,y); 40 sz[y]+=sz[x]; 41 f[x]=y; 42 } 43 44 int radius(int x){ 45 return (len[x]+1)/2; 46 } 47 48 void merge2(int x,int y){ 49 x=find(x),y=find(y); 50 if(x==y)return; 51 if(sz[x]>sz[y])swap(x,y); 52 sz[y]+=sz[x]; 53 f[x]=y; 54 len[y]=max(max(radius(x)+radius(y)+1,len[x]),len[y]); 55 } 56 57 int main() { 58 scanf("%d%d%d",&n,&m,&q); 59 for(int i=1;i<=n;i++){ 60 f[i]=i; 61 sz[i]=i; 62 len[i]=0; 63 } 64 for(int i=1;i<=m;i++){ 65 int x,y; 66 scanf("%d%d",&x,&y); 67 g[x].push_back(y); 68 g[y].push_back(x); 69 merge(x,y); 70 } 71 for(int i=1;i<=n;i++){ 72 int p=find(i); 73 if(!used[p]){ 74 used[p]=1; 75 len[p]=calc(i); 76 } 77 } 78 while(q--){ 79 int t,x,y; 80 scanf("%d",&t); 81 if(t==1){ 82 scanf("%d",&x); 83 printf("%d\n",len[find(x)]); 84 }else{ 85 scanf("%d%d",&x,&y); 86 merge2(x,y); 87 } 88 } 89 }