Codeforces 734E Anton and Tree【并查集缩点||DFS缩点+树的直径】

来源:互联网 发布:优酷怎么在mac下缓存 编辑:程序博客网 时间:2024/06/05 19:12


E. Anton and Tree

time limit per test  3 seconds

memory limit per test      256 megabytes


Anton is growinga tree in his garden. In case you forgot, the tree is a connected acyclicundirected graph.

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

To change thecolors Anton can use only operations of one type. We denote it aspaint(v), where v is some vertexof the tree. This operation changes the color of all verticesu such that all vertices on the shortest path fromv tou have the samecolor (includingv andu). For example, consider the tree

and apply operationpaint(3) to get the following:

Anton isinterested in the minimum number of operation he needs to perform in order tomake the colors of all vertices equal.

Input

The first lineof the input contains a single integern (1 ≤ n ≤ 200 000) — thenumber of vertices in the tree.

The second linecontainsn integerscolori (0 ≤ colori ≤ 1) — colors of the vertices. colori = 0 means that the i-th vertex isinitially painted white, whilecolori = 1 means it's initially painted black.

Then follown - 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'sguaranteed that all pairs(ui, vi) are distinct, i.e. there are no multiple edges.

Output

Print one integer — the minimumnumber of operations Anton has to apply in order to make all vertices of thetree 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 2
2 3
3 4

Output

0

Note

In the first sample, the tree is the same as on the picture. If we first apply operationpaint(3) and then apply paint(6), the tree will become completely black, so the answer is 2.

In the second sample, the tree isalready white, so there is no need to apply any operations and the answer is0.

 


【题意】给出一个有n个点,n-1条边的图(树),每个点都有一种颜色(黑或白),你可以进行若干次操作,每次操作能让一种颜色的联通块反色(从黑到白,从白到黑),求最少操作次数让所有点的颜色相同。

【思路】由于每次操作能让一个联通块反色,我们先把树上所有联通块缩成一个点。缩点后我们重新建图,显然还是一棵树,而且是一颗黑白相间的树。分析可知我们只需要改变树的最长链上的点的颜色即可,设树的直径为d,那么直径上就有d+1个点,每次改变一个点的颜色后都会让它与相邻的点的颜色相同,由于点是黑白相间的,所以只需改变(d+1)/2个点的颜色即可,而分支上的点在最长链上的点改变颜色是已经变成同一颜色了。

缩点方法比较多,并查集,BFS,DFS均可,由于BFS,DFS类似,这里给出并查集缩点和DFS缩点的代码。


一、并查集缩点(436ms)

#include <cstdio>#include <map>#include <vector>#include <iostream>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))#define rush() int T;scanf("%d",&T);while(T--)typedef long long ll;const int maxn = 200005;const int mod = 100000000;const int INF = 0x3f3f3f;const double eps = 1e-9;int n;int root,Max;int pre[maxn],Rank[maxn];int color[maxn];int a[maxn][2];vector<int>vec[maxn];int find(int x){    int t,r=x;    while(x!=pre[x])    {        x=pre[x];    }    while(r!=x)    {        t=pre[r];        pre[r]=x;        r=t;    }    return x;}void join(int a,int b){    int A=find(a);    int B=find(b);    if(A==B) return;    if(Rank[A]<Rank[B])        pre[A]=B;    else    {        pre[B]=A;        if(Rank[A]==Rank[B])            Rank[A]++;    }}void dfs(int u,int pre,int dis){    if(dis>Max)    {        Max=dis;        root=u;    }    for(int i=0;i<vec[u].size();i++)    {        int v=vec[u][i];        if(v==pre) continue;        dfs(v,u,dis+1);    }}int main(){    while(~scanf("%d",&n))    {        for(int i=1;i<=n;i++)        {            scanf("%d",&color[i]);            pre[i]=i;            Rank[i]=0;            vec[i].clear();        }        int x,y;        for(int i=1;i<n;i++)        {            scanf("%d%d",&x,&y);            a[i][0]=x;            a[i][1]=y;            if(color[x]==color[y])                join(x,y);        }        map<int,int>mp;        int cnt=1;        for(int i=1;i<n;i++)        {            if(find(a[i][0])!=find(a[i][1]))            {                int u,v;                u=find(a[i][0]);                v=find(a[i][1]);                if(mp[u]==0) mp[u]=cnt++;                if(mp[v]==0) mp[v]=cnt++;                u=mp[u];                v=mp[v];                vec[u].push_back(v);                vec[v].push_back(u);            }        }        root=1;        Max=0;        dfs(root,-1,0);        Max=0;        dfs(root,-1,0);        printf("%d\n",(Max+1)/2);    }    return 0;}


二、DFS缩点(249ms)

#include <cstdio>#include <map>#include <vector>#include <iostream>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))#define rush() int T;scanf("%d",&T);while(T--)typedef long long ll;const int maxn = 200005;const int mod = 100000000;const int INF = 0x3f3f3f;const double eps = 1e-9;int n;int root,Max;int color[maxn];int depth[maxn];     //某个点所在联通块编号int vis[maxn];vector<int>vec[maxn];vector<int>vec2[maxn];void suodian(int u,int c,int num){    if(vis[u]==1||color[u]!=c) return;    vis[u]=1;    depth[u]=num;    for(int i=0;i<vec[u].size();i++)    {        int v=vec[u][i];        suodian(v,c,num);    }}void dfs(int u,int pre,int dis){    if(dis>Max)    {        Max=dis;        root=u;    }    for(int i=0;i<vec2[u].size();i++)    {        int v=vec2[u][i];        if(v==pre) continue;        dfs(v,u,dis+1);    }}int main(){    while(~scanf("%d",&n))    {        for(int i=1;i<=n;i++)        {            scanf("%d",&color[i]);            vec[i].clear();            vec2[i].clear();            depth[i]=0;        }        int u,v;        for(int i=1;i<n;i++)        {            scanf("%d%d",&u,&v);            vec[u].push_back(v);            vec[v].push_back(u);        }        mst(vis,0);        int cnt=1;        for(int i=1;i<=n;i++)        {            if(vis[i]==0)            {                suodian(i,color[i],cnt);                cnt++;            }        }        for(int i=1;i<=n;i++)        {            if(vec[i].size()==0) continue;            for(int j=0;j<vec[i].size();j++)            {                int v=vec[i][j];                if(depth[i]!=depth[v])                    vec2[depth[i]].push_back(depth[v]);            }        }        root=1;        Max=0;        dfs(root,-1,0);        Max=0;        dfs(root,-1,0);        printf("%d\n",(Max+1)/2);    }    return 0;}




原创粉丝点击