Codeforces 455C Civilization(并查集+树形dp)

本文介绍了解决Codeforces455C问题的方法,使用并查集判断区域连接状态,并通过两次深度优先搜索(DFS)确定区域内最长路径。此外,文章提供了完整的C++代码实现。

Codeforces 455C

题目

中文题意http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1427

思路

判断是否在一个区域用并查集就可以实现,求最长路径我用的是两遍dfs,就可以求出,对于合并,去两个区域最长部分的中间点连边,保证最短,貌似dfs很慢,递归的并查集还超了。

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=3*1e5+10;

int n,m,q;
int tot,head[maxn];
int fa[maxn],len[maxn];
int maxx,id;

struct node
{
    int next;
    int to;
} edge[maxn];

void addedge(int from,int to)
{
    edge[tot].to=to;
    edge[tot].next=head[from];
    head[from]=tot++;
}

int Find(int x)
{
    int k, j, r;
    r = x;
    while(r != fa[r])     
        r = fa[r];      
    k = x;
    while(k != r)             
    {
        j = fa[k];         
        fa[k] = r;       
        k = j;                    
    }
    return r;         
}
void dfs1(int u,int fa,int dep)
{
    if(dep>maxx)
    {
        maxx=dep;
        id=u;
    }
    for(int i=head[u]; ~i; i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa) continue;
        dfs1(v,u,dep+1);
    }
}

int main()
{
    memset(head,-1,sizeof(head));
    memset(len,-1,sizeof(len));
    tot=0;
    scanf("%d %d %d",&n,&m,&q);
    for(int i=1; i<=n; i++)
        fa[i]=i;
    for(int i=0; i<m; i++)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        addedge(a,b);
        addedge(b,a);
        int x=Find(a);
        int y=Find(b);
        fa[x]=y;
    }
    for(int i=0; i<q; i++)
    {
        int op;
        int a,b;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d",&a);
            int x=Find(a);
            if(len[x]==-1)
            {
                maxx=0,id=x;
                dfs1(x,-1,0);
                maxx=0;
                dfs1(id,-1,0);
                printf("%d\n",len[x]=maxx);
            }
            else
                printf("%d\n",len[x]);
        }
        else if(op==2)
        {
            scanf("%d %d",&a,&b);
            int x=Find(a);
            int y=Find(b);
            if(x==y) continue;
            if(len[x]==-1)
            {
                maxx=0,id=x;
                dfs1(x,-1,0);
                maxx=0;
                dfs1(id,-1,0);
                len[x]=maxx;
            }
            if(len[y]==-1)
            {
                maxx=0,id=y;
                dfs1(y,-1,0);
                maxx=0;
                dfs1(id,-1,0);
                len[y]=maxx;
            }
            fa[x]=y;
            int t1=len[x]%2==0?len[x]/2:len[x]/2+1;
            int t2=len[y]%2==0?len[y]/2:len[y]/2+1;
            len[y]=max(t1+t2+1,max(len[x],len[y]));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值