1. 程式人生 > 實用技巧 >CF734E Anton and Tree(並查集+樹的直徑)

CF734E Anton and Tree(並查集+樹的直徑)

題目連結:https://www.luogu.com.cn/problem/CF734E

首先用並查集將題目中原先的相鄰的顏色相同的點進行縮點,用並查集來完成。然後考慮如何改變是最優的。將縮點後的點建樹,找到樹的直徑,不斷改變直徑的中點及其相鄰顏色塊的顏色,會讓整個樹在floor(len+1)次完成改變全部顏色(len為直徑長度)。其他不是直徑的枝葉會在改變直徑時直接改變掉。

AC程式碼:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5
#include<cmath> 6 #include<queue> 7 using namespace std; 8 const int N=200005; 9 int n,tot,maxd; 10 queue<int> q; 11 int x[N],y[N],c[N],head[N],f[N],vis[N],d[N]; 12 struct node{ 13 int to,next; 14 }edge[N<<1]; 15 void init(){ 16 memset(head,-1,sizeof(head)); 17 } 18 int
find(int x){ 19 if(f[x]!=x) f[x]=find(f[x]); 20 return f[x]; 21 } 22 void add(int u,int v){ 23 edge[tot].next=head[u]; 24 edge[tot].to=v; 25 head[u]=tot++; 26 } 27 int BFS(int s){ 28 int pos; 29 maxd=0; 30 memset(d,0,sizeof(d)); 31 memset(vis,0,sizeof(vis)); 32 while
(!q.empty()) q.pop(); 33 q.push(s); vis[s]=1; 34 while(!q.empty()){ 35 int u=q.front(); q.pop(); 36 for(int i=head[u];i!=-1;i=edge[i].next){ 37 int v=edge[i].to; 38 if(vis[v]) continue; 39 vis[v]=1; 40 d[v]=d[u]+1; 41 q.push(v); 42 if(maxd<d[v]){ 43 maxd=d[v]; 44 pos=v; 45 } 46 } 47 } 48 return pos; 49 } 50 int main(){ 51 init(); 52 scanf("%d",&n); 53 for(int i=1;i<=n;i++) scanf("%d",&c[i]); 54 for(int i=1;i<=n;i++) f[i]=i; 55 for(int i=1;i<n;i++){ 56 scanf("%d%d",&x[i],&y[i]); 57 int r1=find(x[i]),r2=find(y[i]); 58 if(c[r1]==c[r2]) f[r1]=r2; 59 } 60 for(int i=1;i<=n;i++) f[i]=find(f[i]);//縮點 61 for(int i=1;i<n;i++) if(f[x[i]]!=f[y[i]]) add(f[x[i]],f[y[i]]),add(f[y[i]],f[x[i]]); 62 int l=BFS(f[x[1]]); 63 BFS(l); 64 int ans=floor((maxd+1)/2); 65 printf("%d",ans); 66 return 0; 67 }
AC程式碼