codeforces 455C Civilization 树的最长链+并查集

来源:互联网 发布:淘宝男迷彩加绒衫 编辑:程序博客网 时间:2024/05/21 11:18

题意:

给定n个城市和m个道路,在同一个连通块的城市为一个区域。

有两个操作,第一个操作:询问第x个城市所在的区域最长链是多少。第二个操作:将第x个城市所在的区域和第y个城市所在的区域相连接,要求连接后的最长链最短。

思路:

先来考虑第一个操作,求连通域内最长链可用两次dfs,然后我们记录下最长链中间的结点,令len[u][0]和len[u][1]分别为最长链左边的长度和右边的长度,然后将其余结点的根节点设改该结点,用并查集,则每次查询只用找到询问结点的根结点即可。

第二个操作则,若要求连接后的最长链最短,则一定是将两个区域的根结点相连,相连之后令一个区域根节点为另一个区域根节点,更新len[u][0]和len[u][1],具体更新看代码。

#include<cstdio>#include<cstring>#include<algorithm>#include<vector>#define mem(name,value) memset(name,value,sizeof(name))#define FOR(i,n) for(int i=1;i<=n;i++)using namespace std;const int maxn = 3*100000+10;int path[maxn],len[maxn][2],p[maxn];int path_max,path_start,path_mid;bool vis[maxn];vector<int>G[maxn];void dfs1(int s,int cur,int f){ //第一次dfs找到最长链的起点    if(cur>=path_max){        path_max = cur;        path_start = s;    }    for(int i=0;i<G[s].size();i++)        if(G[s][i]!=f) dfs1(G[s][i],cur+1,s);}void dfs2(int s,int cur,int f){//第二次dfs算出最长链和找到最长链的中间结点    path[cur]=s;    if(cur>=path_max){        path_max = cur;        path_mid = path[cur/2];    }    for(int i=0;i<G[s].size();i++)        if(G[s][i]!=f) dfs2(G[s][i],cur+1,s);}void dfs3(int s,int f){ //第三次dfs将其余点都设为该结点的子节点,并标记所有访问过的结点    vis[s]=true;    p[s] = path_mid;    for(int i=0;i<G[s].size();i++)        if(G[s][i]!=f) dfs3(G[s][i],s);}int find_set(int x){return p[x]==x ? x : p[x]=find_set(p[x]);}void merge_set(int a,int b){    int x = find_set(a), y = find_set(b);    if(x==y) return ;    int x1 = max(len[x][0],len[x][1]);    int y1 = max(len[y][0],len[y][1]);    if(x1<y1) swap(x,y);    p[y] = x;    x1 = max(len[x][0],len[x][1]);    y1 = max( min(len[x][0],len[x][1]),max(len[y][0],len[y][1])+1 );    len[x][0] = x1; len[x][1] = y1;}int main(){    //freopen("in.txt","r",stdin);    int n,m,q,tmp,x,y;    scanf("%d%d%d",&n,&m,&q);    for(int i=0;i<m;i++){        scanf("%d%d",&x,&y);        G[x].push_back(y);        G[y].push_back(x);    }    mem(vis,false); mem(len,0);    for(int i=1;i<=n;i++){        if(!vis[i]){            path_max = 0;            dfs1(i,0,-1);            dfs2(path_start,0,-1);            dfs3(path_mid,-1);            len[path_mid][0]=path_max / 2;            len[path_mid][1] = path_max - len[path_mid][0];        }    }    for(int i=0;i<q;i++){        scanf("%d",&tmp);        if(tmp==1){            scanf("%d",&x);            tmp = find_set(x);            printf("%d\n",len[tmp][0]+len[tmp][1]);        }else{            scanf("%d%d",&x,&y);            merge_set(x,y);        }    }    return 0;}


 

0 0
原创粉丝点击