树上基因重组

文章描述了一个关于数据结构和算法的问题,给定一棵有根树的深度优先搜索(DFS)序和每个节点的子树大小,要求根据这些信息重建原树。提供的C++代码实现了一个DFS函数来解决这个问题,通过维护父子关系构建边,最后输出重建树的边连接顺序。
摘要由CSDN通过智能技术生成

链接:https://ac.nowcoder.com/acm/contest/51721/C

来源:牛客网

题目描述

小松鼠又开始研究树的基因了,他开发出了一种基因重组算法,能根据一些信息很快地还原一棵树,现在他想考考你!

给定一棵 nnn 个节点的有根树的 dfs 序以及每个点对应的子树大小,求这棵树。

保证有解哦!

输入描述:

输入共三行。第一行为节点数 n (2≤n≤106)n\ (2\leq n\leq 10^6)n (2≤n≤106),第二行为这棵树的 dfs 序,第三行为以 1∼n1\sim n1∼n 为根的每棵子树大小。

输出描述:

输出共 n−1n-1n−1 行。每行两个正整数表示 (u,v)(u,v)(u,v),要求 u<vu<vu<v 并且每行的 uuu 单调不降,对于相同的 uuu 所对应的 vvv 需要满足单调递增。

示例1

输入

复制

4

1 2 4 3

4 2 1 1

输出

复制

1 2

1 3

2 4

说明

树的形态如下图所示:

示例2

输入

复制

3

3 1 2

1 1 3

输出

复制

1 3

2 3

说明

第一次给出了dfs序即递归执行过程

所以我们只要在每次递归的过程中维护好父亲和儿子的关系就ok

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define YES cout<<"YES"<<endl
#define NO cout<<"NO"<<endl
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
const int N = 1e6+10;
int d[N];int g[N];
#define ios ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
int cnt=1;
vector<PII>p;
void dfs(int x)
{
    g[x]--;
    while(g[x])
    {
        int v=d[++cnt];
        p.push_back({x,v});
        g[x]-=g[v];
        dfs(v);
    }
}

void solve()
{    
    int n;cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>d[i];
    }
    for(int i=1;i<=n;i++)
    {
        cin>>g[i];
    }
    dfs(d[cnt]);
    int len=p.size()-1;
    for(int i=0;i<=len;i++)
    {
        auto [x,y]=p[i];
        if(x>y)
        {
            swap(p[i].first,p[i].second);
        }        
    }
    sort(p.begin(),p.end());
    for(auto [x,y] : p)
    {
       cout<<x<<" "<<y<<endl;
    }    
}

signed main()
{
    int t;
    t=1;
    while(t--)
    {
        solve();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值