题目链接
734 E Anton and Tree
题目大意:一棵树上有两种不同颜色的节点,你有一种操作,一次可以改变与
v
相连的同种颜色联通快的颜色,问最少多少次操作可以把树染成同样的颜色
分析
看了题解之后才明白了,因为一次染色可以改变同一个连通块,所以首先想到把同一个连通块缩成一个节点,这样是不影响染色操作的,这样我们就只需要考虑一颗相邻节点颜色不同的树需要多少次操作才能把颜色变为一样的了,
首先我们指出染色操作不可能少于
下面我们证明最小染色次数就是
(floor[(d+1)/2])
,我们可以用induction来证明,
d=0
的时候是显然的,下面我们来推
d=n
的时候成立
首先,树的直径上的点的非直径分支的长度不可能长于他在直径上的最短分支的长度,那么我们可以在直径上找到一个非树上分支最长的节点(不选端点),对他染色,这样可以保证染色缩点后的树
T′
的直径还经过原来的树
T
,因为此时仍能够保证这条直径上的点的非直径分支不超过直径上的分支。这样我们就归约到了
(floor[(d+1)/2])
题解原文,(我的证明和原文不一样)
所以这道题只需要缩点求直径,个人代码功底太弱写的很挫~
AC代码
#include <cstdio>
#include <cstring>
#include <queue>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<vector>
#define INF 0x3f3f3f3f
#define maxn 200009
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef unsigned long long uLL;
typedef pair<int,int> PI;
struct Edge{
int u,v;
};
int ans;
int color[maxn];
int p[maxn];
bool vis[maxn];
int find(int x){return p[x] == x? x:p[x] = find(p[x]);}
void Union(int x,int y)
{
x = find(x),y = find(y);
if(x!=y)p[x] = y;
}
struct Graph{
Edge edges[maxn*2];
int n,ne;
int ft[maxn];
int nt[maxn*2];
int d[maxn];
void init()
{
ne = 0;
memset(ft,-1,sizeof(ft));
memset(nt,-1,sizeof(nt));
memset(d,0,sizeof(d));
}
void add_edge(int u,int v)
{
edges[ne].u = u,edges[ne].v = v;
nt[ne] = ft[u];
ft[u] = ne;
ne++;
}
void bfs(int s)
{
queue<int> Q;
Q.push(s);
d[s] = 0;
while(!Q.empty())
{
int u = Q.front();Q.pop();
for(int e = ft[u] ; e!=-1 ; e = nt[e])
{
int v = edges[e].v;
if(d[v]==0 && v!=s){
d[v] = d[u]+1;
Q.push(v);
}
}
}
}
int diamiter()
{
int s = find(1);
bfs(s);
s = 1;
for(int i=1 ; i<n ; ++i)
if(d[s]<d[i])s = i;
memset(d,0,sizeof(d));
bfs(s);
int res = -1;
for(int i=1 ; i<=n ; ++i)
res = max(res,d[i]);
return res;
}
};
Graph G1,G2;
//并查集缩点
void compress(Graph & G)
{
for(int i=0 ; i<G.ne ; ++i)
{
int u = G.edges[i].u,v = G.edges[i].v;
if(color[u] == color[v])Union(u,v);
}
}
//建新树
void dfs(int s,int p)
{
vis[s] = true;
for(int e = G1.ft[s] ; e!=-1 ; e = G1.nt[e])
{
int v = G1.edges[e].v;
if(color[v]!=color[p])G2.add_edge(p,find(v));
else if(!vis[v])dfs(v,p);
}
}
int main()
{
//freopen("H:\\c++\\file\\stdin.txt","r",stdin);
int n;
cin>>n;
G1.init();G2.init();
for(int i=1 ; i<=n ; ++i)p[i] = i;
memset(vis,false,sizeof(vis));
G1.n = G2.n = n;
for(int i=1 ; i<=n ; ++i)cin>>color[i];
for(int i=0 ; i<n-1 ; ++i)
{
int u,v;
cin>>u>>v;
G1.add_edge(u,v);
G1.add_edge(v,u);
}
compress(G1);
for(int i=1 ; i<=n ; ++i)
if(p[i] == i)dfs(i,i);
int ans = G2.diamiter();
cout<<(ans+1)/2<<endl;
return 0;
}