题目链接: Anton and Tree
题意:给出一棵树由0和1构成,一次操作可以将树上一块相同的数字转换为另一个(0->1 , 1->0),求最少几次操作可以把这棵数转化为只有一个数字的一棵数。
题解:首先一次可以改变一片数字,那么进行缩点后就变成了每次改变一个点。缩完点后这棵数变成了一棵相邻节点不同,0和1相交叉的一棵树。然后一棵树的直径上就是
0 1 0 1 0 1 0 1 0
这种情况,相当于从中间开始操作,总共操作(L+1)/2次。关于其他的分支一定会在直径的改变过程中完成改变。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAX_N = 2e5+9; 4 const long long INF = 1e9+8; 5 typedef pair<int,int> P; 6 int N,M,T; 7 vector<P> V; 8 int dir[MAX_N]; 9 int vec[MAX_N]; 10 int father[MAX_N]; 11 int vis[MAX_N]; 12 vector<int> tran[MAX_N]; 13 int start,deep; 14 void init(){ 15 for(int i=0;i<MAX_N;i++){ 16 dir[i] = i; 17 tran[i].clear(); 18 vis[i] = 0; 19 } 20 V.clear(); 21 start = -1; 22 deep = 0; 23 } 24 int find_f(int x){ 25 if(x == dir[x]) return x; 26 return dir[x] = find_f(dir[x]); 27 } 28 void bfs(int pos,int deepth){ 29 if(deepth > deep){ 30 deep = deepth; 31 start = pos; 32 //cout<<"....."<<deepth<<endl; 33 } 34 vis[pos] = 1; 35 for(int i=0;i<tran[pos].size();i++){ 36 if(!vis[tran[pos][i]]) bfs(tran[pos][i],deepth+1); 37 } 38 return ; 39 } 40 int main() 41 { 42 while(cin>>N){ 43 init(); 44 for(int i=1;i<=N;i++){ 45 scanf("%d",&vec[i]); 46 } 47 for(int i=0;i<N-1;i++){ 48 int a,b; 49 scanf("%d%d",&a,&b); 50 int fa = find_f(a); 51 int fb = find_f(b); 52 if(vec[fa] == vec[fb] ) dir[fb] = dir[fa]; 53 else V.push_back(P(fa,fb)); 54 } 55 for(int i=1;i<=N;i++){ 56 father[i] = find_f(i); 57 } 58 for(int i=0;i<V.size();i++){ 59 P p = V[i]; 60 //cout<<father[p.first]<<"...."<<father[p.second]<<endl; 61 tran[father[p.first]].push_back(father[p.second]); 62 tran[father[p.second]].push_back(father[p.first]); 63 start = father[p.first]; 64 } 65 if(start == -1) { 66 cout<<0<<endl; 67 } 68 else{ 69 bfs(start,0); 70 deep = 0; 71 for(int i=0;i<=N;i++) vis[i] = 0; 72 bfs(start,0); 73 cout<<(deep+1)/2<<endl; 74 } 75 76 } 77 return 0; 78 } 79 /* 80 81 82 */