8
20
2014
0

Codeforces Round#260E

先把这几天要填的坑填完……T T

题意 by hongrock (语文水平及表达水平不高借鉴别人的题目翻译……)

 

题目就是N个点的无向图,先给出M条边,这M条边使得任意两点间要么不连通,要么仅有唯一的路径相连。

两个点如果连通就说明它们在同一个区域。

然后Q个询问

1 x,输出x所在区域的最长路径;

2 x y,如果x和y在同一区域则忽略,否则合并两个区域,并且合并之后的新区域的最长路径应该是最短的。

 

大概是这样……还要注意一点就是边的权值都为1.

然后比较容易想到用并查集来动态合并+维护区域信息。然后是要输出区域中的最长路径……合并的时候也要维护最

长路,使得其合并后是最短的,那么容易想到预处理出每个区域的直径……(其实就是类似树的直径),然后合并的

时候因为要求新的区域的最长路最短,那么我们定义一个点的最远距离是他到其他点的最远距离,我们合并直径是各

选一个最远距离最小的点,可以证明这个点一定是直径的中点。那么接下来就比较显然了,这个新的最长路一定是

max((path[y]+1)/2+(path[x]+1)/2+1,path[x],path[y])。还有求树的直径的话我这里就两次BFS即可,具体过程就是先选取一点u,跑出u的最远点yuan,然后从yuan跑出yuan的最远点y2,这时候y2和yuan之间的距离即为树的直径。证明这里就不证了,其实挺显然的……

 

~感谢skydec大爷的标程及其对题目思路的提示!

 

#include<iostream>  
#include<cstring>  
#include<cstdio>  
#include<algorithm>  
#include<vector>  
#include<string>  
#include<set>  
#include<queue>  
#include<stack>  
#include<map>  
#include<cmath>  
#include<cstdlib>  
#define ll long long  
#define maxn 600010  
#define inf 1000000000  
#define linf (1LL<<50)  
using namespace std;  
inline ll read()  
{  
    ll x=0,f=1;char ch=getchar();  
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  
    while(ch>='0'&&ch<='9'){x*=10;x+=ch-'0';ch=getchar();}  
    return x*f;  
}  
  
inline void read(char *s,int &ts)  
{  
    char x=getchar();  
    while(!(x>='a'&&x<='z'))x=getchar();  
    while(x>='a'&&x<='z')s[++ts]=x,x=getchar();  
}  
int n,m,que,tot=0;  
int q[maxn];  
struct data{  
    int to,next;  
}e[2*maxn];  
int head[maxn];  
int path[maxn];  
int d[maxn];  
int flag[maxn];  
int f[maxn];  
void line(int a,int b)  
{  
    tot++;  
    e[tot].to=b;  
    e[tot].next=head[a];  
    head[a]=tot;  
}  
int get(int x)  
{   
    return(x==f[x])?x:f[x]=get(f[x]);  
}  
int find(int x)  
{  
    d[x]=0;  
    flag[x]=x;  
    q[q[0]=1]=x;  
    int yuan=x;  
    for(int i=1;i<=q[0];i++)  
    {  
        int y=q[i];  
        for(int u=head[y];u;u=e[u].next)  
        if(flag[e[u].to]!=x)  
        {  
            flag[e[u].to]=x;  
            q[++q[0]]=e[u].to;  
            d[e[u].to]=d[y]+1;  
            if(d[e[u].to]>d[yuan])   
            yuan=e[u].to;  
        }  
    }  
    int y2=yuan;  
    d[yuan]=0;  
    q[q[0]=1]=yuan;  
    flag[yuan]=yuan;  
    for(int i=1;i<=q[0];i++)  
    {  
        int y=q[i];  
        for(int u=head[y];u;u=e[u].next)  
        if(flag[e[u].to]!=yuan)  
        {  
            flag[e[u].to]=yuan;  
            q[++q[0]]=e[u].to;  
            d[e[u].to]=d[y]+1;  
            if(d[e[u].to]>d[y2])  
            y2=e[u].to;  
        }  
    }  
    return d[y2];  
}  
  
int main()  
{  
    scanf("%d%d%d",&n,&m,&que);  
    for(int i=1;i<=n;i++)  
    f[i]=i;  
    for(int i=1;i<=m;i++)  
    {  
        int x,y;  
        scanf("%d%d",&x,&y);  
        line(x,y);  
        line(y,x);  
        if(get(x)!=get(y))  
        f[get(x)]=get(y);  
    }  
    for(int i=1;i<=n;i++)  
    if(i==get(i)) path[i]=find(i);  
    for(int i=1;i<=que;i++)  
    {  
        int pos;  
        scanf("%d",&pos);  
        if(pos==1)  
        {  
            int x;  
            scanf("%d",&x);  
            printf("%d\n",path[get(x)]);  
        }  
        else  
        {  
            int x,y;  
            scanf("%d%d",&x,&y);  
            x=get(x);y=get(y);  
            if(x==y) continue;  
            int u1=path[x];  
            int u2=path[y];  
            f[x]=y;  
            path[y]=(u1+1)/2+(u2+1)/2+1;  
            if(path[y]<u1) path[y]=u1;  
            if(path[y]<u2) path[y]=u2;  
        }  
    }  
    return 0;  
}  
Category: codeforces | Tags: 并查集 树的直径 | Read Count: 733

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com