您的位置:首页 > 其它

codeforces 734e(连通分量缩点)

2017-10-23 13:45 357 查看
E. Anton and Tree

time limit per test
3 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

Anton is growing a tree in his garden. In case you forgot, the tree is a connected acyclic undirected graph.

There are n vertices in the tree, each of them is painted black or white. Anton doesn't like multicolored trees, so he wants to change
the tree such that all vertices have the same color (black or white).

To change the colors Anton can use only operations of one type. We denote it as paint(v), where v is
some vertex of the tree. This operation changes the color of all vertices u such that all vertices on the shortest path from v to u have
the same color (including v andu).
For example, consider the tree



and apply operation paint(3) to get the following:



Anton is interested in the minimum number of operation he needs to perform in order to make the colors of all vertices equal.

Input

The first line of the input contains a single integer n (1 ≤ n ≤ 200 000) —
the number of vertices in the tree.

The second line contains n integers colori (0 ≤ colori ≤ 1) —
colors of the vertices. colori = 0 means
that the i-th vertex is initially painted white, while colori = 1 means
it's initially painted black.

Then follow n - 1 line, each of them contains a pair of integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) —
indices of vertices connected by the corresponding edge. It's guaranteed that all pairs (ui, vi) are
distinct, i.e. there are no multiple edges.

Output

Print one integer — the minimum number of operations Anton has to apply in order to make all vertices of the tree black or all vertices of the tree white.

Examples

input
11
0 0 0 1 1 0 1 0 0 1 1
1 2
1 3
2 4
2 5
5 6
5 7
3 8
3 9
3 10
9 11


output
2


input
4
0 0 0 0
1 22 3
3 4


output
0


题意:包含n个点的一棵树,每个点都有黑白两种颜色,每改变一个节点的颜色,他周围和它颜色相同的节点也变色(一整块颜色相同的点),求让这棵树变成同一种颜色的最小操作。

思路:利用连通量缩点,重新建图,求出最远两个节点的距离x,(x+1)/2就是答案

看了别人题解用模板写了个很挫的代码。。。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX_V 200005
int V;
int ans;
vector<int>G[MAX_V]; //原图
vector<int>rG[MAX_V]; //反向边图
vector<int>gc[MAX_V]; //缩点之后的图
vector<int>vs; //后序遍历顶点序列
bool used[MAX_V]; //访问标记
int cmp[MAX_V]; //所属强连通分量拓扑序
bool color[MAX_V]; //颜色
int dp[MAX_V]; //记录每个点到其他所有点中最远点的距离
void add_edge(int from,int to)
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(int v) //第一次dfs
{
used[v]=true;
for(int i=0;i<G[v].size();i++)
{
if(!used[G[v][i]])dfs(G[v][i]);
}
vs.push_back(v);
}
void rdfs(int v,int k) //第二次dfs
{
used[v]=true;
cmp[v]=k;
for(int i=0;i<rG[v].size();i++)
{
if(!used[rG[v][i]])rdfs(rG[v][i],k);
}
}
int scc()
{
memset(used,0,sizeof(used));
vs.clear();
for(int v=0;v<V;v++)
{
if(!used[v])dfs(v);
}
memset(used,0,sizeof(used));
int k=0;
for(int i=vs.size()-1;i>=0;i--)
{
if(!used[vs[i]])
{
rdfs(vs[i],k++);
}
}
return k;
}

void DFS(int u,int fa)
{
int mx=0,mmx=0;//mx是点到图的任意一点的最远距离,mmx是次远距离
for(int i=0;i<gc[u].size();i++)
{
int v=gc[u][i];
if(v==fa) continue;//防止遍历回父节点
DFS(v,u);
mmx=max(mmx,dp[v]+1);
if(mmx>mx) swap(mmx,mx);
}
dp[u]=mx;
ans=max(ans,mx+mmx);//图的直径等于某个点的最远距离加上次远距离
}
void init()
{
ans=0;
for(int i=0;i<MAX_V;i++)
{
G[i].clear();
rG[i].clear();
gc[i].clear();
}
vs.clear();
memset(used,0,sizeof(used));
memset(cmp,0,sizeof(cmp));
memset(color,0,sizeof(color));
memset(dp,0,sizeof(dp));
}
int main()
{
while(~scanf("%d",&V))
{

for(int i=0;i<V;i++)scanf("%d",&color[i]);
int f,t;
for(int i=0;i<V-1;i++)
{
scanf("%d%d",&f,&t);
if(color[f-1]==color[t-1]) //如果两点颜色一样就是无向边,颜色不一样就是有向边
{
add_edge(f-1,t-1);
add_edge(t-1,f-1);
}
else add_edge(f-1,t-1);
}
int h=scc();
//重新建图
for(int i=0;i<V;i++)
{
for(int j=0;j<G[i].size();j++)
{
int v=G[i][j];
if(cmp[v]!=cmp[i])
{
gc[cmp[v]].push_back(cmp[i]);
gc[cmp[i]].push_back(cmp[v]);
}
}
}
DFS(0,-1);
printf("%d\n",(ans+1)/2);
}
}下面是别人的代码:http://blog.csdn.net/pan1197349032/article/details/53217462
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = (1ULL<<63)-1;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=200010;
const ll MOD=1000000007;
const double eps=1e-3;
const double pi=acos(-1.0);
using namespace std;
vector<int> g
,gc
;//g是原图,gc是缩点后的图
int n,u,v,ans,cnt;
int vis
,col
,comp
,dp
;//dp储存该点到图的任意一点的最远距离,comp是该点属于缩点后的图的哪一点
void dfs(int u,int c,int rt) //缩点操作
{
if(vis[u]||col[u]!=c) return;
vis[u]=1;
comp[u]=rt;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
dfs(v,c,rt);
}
}
void DFS(int u,int fa)
{
int mx=0,mmx=0;//mx是点到图的任意一点的最远距离,mmx是次远距离
for(int i=0;i<gc[u].size();i++)
{
int v=gc[u][i];
if(v==fa) continue;//防止遍历回父节点
DFS(v,u);
mmx=max(mmx,dp[v]+1);
if(mmx>mx) swap(mmx,mx);
}
dp[u]=mx;
ans=max(ans,mx+mmx);//图的直径等于某个点的最远距离加上次远距离
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&col[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);g[v].push_back(u);
}
for(i=1;i<=n;i++)
{
if(vis[i]==0) dfs(i,col[i],++cnt);
}
for(i=1;i<=n;i++)
{
for(j=0;j<g[i].size();j++)
{
int v=g[i][j];
if(comp[v]!=comp[i]) gc[comp[i]].push_back(comp[v]);
}
}
DFS(1,-1);
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: