codeforces gym100519 problemG Genealogy(topu)

链接

题意:

给出n个人以及他的父亲,询问家族关系中最长的一条链,可以有环。



思路:

每个人的儿子可以有多个,但是父亲只有一个或者没有。先考虑简单的情况,没有环的话,就类似于森林,建一条儿子指向父亲的单向边,从叶子出发topu,记录一下每个点向下延申的最大距离即可。如果有环的话,不难发现,环上挂着的链的方向都是指向环的,答案就会变为环的周长+挂着的最长的一条链的长度。和之前一样从叶子topu,环上有链的点都记录了该点所链的最大长度,topu结束后,dfs遍历环统计一下环的周长和最长链。



#include <bits/stdc++.h>

#define  _debug(x) cerr<<#x << " = " << x<<endl
using namespace std;

typedef long long ll;
//typedef _int128 lll;
const int MOD = 0;
//const double eps = 1e-3;
const int MAXN = 200000 + 59;
const int INF = 0x3f3f3f3f;
const ll INFll = 0x3f3f3f3f3f3f3f;
const double eps = 1e-9;

unordered_map<string, int> id;
int n, m, ans;
int ind[MAXN];
string sn, fn1, _son, _of, fn2;

struct Edge {
    int v, nx;
} ed[MAXN << 2];

int head[MAXN], cntEd;

void addEdge(int u, int v) {
    ed[cntEd] = {v, head[u]};
    head[u] = cntEd++;
}

int val[MAXN];
queue<int>q;
bool out[MAXN];
void topu(){
    while (!q.empty()){
        int u=q.front();
//        printf("u:%d\n",u);
        out[u]= true;
        q.pop();
        for(int i=head[u];~i;i=ed[i].nx){
            int v=ed[i].v;
            ind[v]--;
            val[v]=max(val[v],val[u]+1);
            ans=max(ans,val[v]);
            if(!ind[v]){
                q.push(v);
            }
        }
    }
}

int tmp;
int r;
void dfs(int u){
    out[u]=true;
    tmp=max(tmp,val[u]);
    r++;
    for(int i=head[u];~i;i=ed[i].nx){
        int v=ed[i].v;
        if(out[v])continue;
        dfs(v);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    memset(head, -1, sizeof head);
    cntEd = 0;

    cin >> n;
    for (int i = 1, u, v; i <= n; ++i) {
        cin >> sn >> fn1 >> _son >> _of >> fn2;
        fn1 = sn + fn1;
        fn2 = sn + fn2;
        if (!id[fn1])id[fn1] = ++m;
        if (!id[fn2])id[fn2] = ++m;

        v = id[fn1];
        u = id[fn2];
        addEdge(v, u);
        ind[u]++;
    }
    ans=1;
    for(int i=1;i<=m;i++){
        if(!ind[i]){
            q.push(i);
        }
    }
    topu();
//    printf("%d\n",ans);
    for(int i=1;i<=m;i++){
        if(!out[i]){
            tmp=0;
            r=0;
            dfs(i);
//            printf("r:%d\n",r);
            ans=max(ans,tmp+r);
        }
    }
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值