Codeforces 455C. Civilization (树的直径+并查集)

来源:互联网 发布:宇宙数控系统编程 编辑:程序博客网 时间:2024/05/18 18:03

题目描述

传送门

题目大意:
(1)询问x所在连通块的最长链
(2)将x,y所在的连通块合并,任意两个点之间可以连边,使合并后连通块的最长链最短。

题解

比较容易想到的是连接的两个点是两棵树的中心(最长链的中点)。
关键是连接后的树中点是否会改变呢?答案是连接后的中心是两棵树中最长链较长的树的中心。
那么我们把一个连通块的代表元素维护成树的中心,在这个点动态维护经过这个点子树中的最长链和次长链。
那么对于询问,就是找到代表元素求最长链和次长链的和。

代码

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 600003using namespace std;int tot,head,p[N],n,m,q,top,st[N],ans,ansx;int point[N],v[N],nxt[N],pre[N],fa[N],pd[N],val[N],f[N],g[N];void add(int x,int y){    tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;     tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void dfs(int x,int f,int d){    st[++top]=x; pd[x]=1;    if (d>ans) {        ans=d; ansx=x;    }    for (int i=point[x];i!=-1;i=nxt[i]){        if (v[i]==f) continue;        pre[v[i]]=i;        dfs(v[i],x,d+1);    }}int getroad(int x,int y){    head=0;    while (x!=y) {        p[++head]=x;        x=v[pre[x]^1];    }    p[++head]=x;    return p[(head+1)/2];}int find(int x){    if (fa[x]==x) return x;    fa[x]=find(fa[x]);    return fa[x];}int main(){    freopen("a.in","r",stdin);    freopen("my.out","w",stdout);    scanf("%d%d%d",&n,&m,&q);    tot=-1;    memset(point,-1,sizeof(point));    for (int i=1;i<=m;i++) {        int x,y; scanf("%d%d",&x,&y);        add(x,y);    }    for (int i=1;i<=n;i++) fa[i]=i;    for (int i=1;i<=n;i++)    if (!pd[i]) {        ansx=ans=-1;        dfs(i,0,0);        int t=ansx; ansx=ans=-1; top=0;        dfs(t,0,0);        int mid=getroad(ansx,t);        val[mid]=ans; f[mid]=ans/2; g[mid]=ans-f[mid];        if (f[mid]<g[mid]) swap(f[mid],g[mid]);        for (int j=1;j<=top;j++) fa[st[j]]=mid;    }    for (int i=1;i<=q;i++) {        int opt,x,y; scanf("%d%d",&opt,&x);        if (opt==1) {            x=find(x);            printf("%d\n",val[x]);        }        else {            scanf("%d",&y);            int r1=find(x); int r2=find(y);            if (r1==r2) continue;            if (val[r1]>val[r2]) {               fa[r2]=r1;               if (f[r2]+1>f[r1]) g[r1]=f[r1],f[r1]=f[r2]+1;               else g[r1]=max(f[r2]+1,g[r1]);               val[r1]=g[r1]+f[r1];            }            else {              fa[r1]=r2;              if(f[r1]+1>f[r2]) g[r2]=f[r2],f[r2]=f[r1]+1;              else  g[r2]=max(g[r2],f[r1]+1);               val[r2]=f[r2]+g[r2];            }        }    }}
阅读全文
0 0