虚假的树状数组

虚假的树状数组

题目信息

一年一度的数据结构发明大赛开始了,小张作为数据结构爱好者积极参加了这次比赛。他将自己参与竞赛的数据结构命名为"虚假的树状数组"。有别于我们常说的树状数组,这个数据结构没有什么实际作用,但还是比较有意思的,因此他光荣的获得了此次大赛的鼓励奖。
"虚假的树状数组"是一个 n 个结点的有向树,每个结点都有一个权值,编号为 i 的结点权值为 ai 。树上的每一个结点可以生成一个数组,生成的方式为:[编号为 x 的结点的生成数组]=[ ax ]+[ x 结点编号最小的儿子结点的生成数组]+…+[ x 结点编号最大的儿子结点的生成数组]。式子中的加号为数组的拼接,例如[1,1,2,1]+[1,2,2,3]=[1,1,2,1,1,2,2,3]
同时,有些结点拥有一个排序标记,拥有排序标记的结点的生成数组需要按照从小到大的顺序排序。
现在,请你求出有向树的根节点的生成数组。

输入

第一行一个整数 n(1 ≤ n ≤ 200000)
第二行 n 个整数,第 i 个整数 ai(1 ≤ a_i ≤ 10^9) 表示编号为 i 的结点权值。
第三行 n 个整数,第 i 个整数 fi(0 ≤ fi ≤ 1) ,0表示编号为 i 的结点没有排序标记,1表示编号为 i 的结点有排序标记。
接下来 n-1 行,每行两个数 x,y(1 ≤ x,y ≤ n),表示编号为x的结点到编号为 y 的结点有一条有向边。数据保证为一个有向树。

输出

用逗号隔开的 n 个整数,表示有向树的根节点的生成数组。用[]括起来。

测试样例

7
12 1 10 8 8 11 2
0 0 0 0 1 0 0
2 3
2 4
2 5
3 1
3 6
5 7
[1,10,12,11,8,2,8]

解答

#include <iostream>
#include <vector>
#include <algorithm>

#define MAXN 200010
using namespace std;

int n;

class Point
{
    
    
public:
    int num;
    int flag;
};

Point points[MAXN];

vector<int> v[MAXN], g[MAXN];
int Root[MAXN];
int root;

struct Rule
{
    
    
    bool operator()(const Point &a, const Point &b) const
    {
    
    
        return a.num < b.num;
    }
};

void dfs(int x)
{
    
    
    v[x].push_back(points[x].num);//将取到的这个点的确切对应的数值压入新图中
    for (int i = 0; i < g[x].size(); i++)
    {
    
    //遍历原图中每一个小节点
        int tmp = g[x][i];
        dfs(tmp);//对每个存在的小节点进行搜索
        for (int j = 0; j < v[tmp].size(); j++)
        {
    
    //逐个将此节点的子节点拷贝到这里,来建立逐层的关系表
            v[x].push_back(v[tmp][j]);
        }
    }

    if (points[x].flag)
    {
    
    //如果图上这个点被标记需要排序,那么此处图底下的所有元素都进行排序
        sort(v[x].begin(), v[x].end());
    }
}

int main()
{
    
    
    //freopen("E://test.txt", "r", stdin);

    cin >> n;
    for (int i = 1; i <= n; i++)
    {
    
    
        cin >> points[i].num;
    }
    for (int i = 1; i <= n; i++)
    {
    
    
        cin >> points[i].flag;
    }

    for (int i = 1; i < n; i++)
    {
    
    //输入的内容存储至g
        int tmpx, tmpy;
        cin >> tmpx >> tmpy;
        g[tmpx].push_back(tmpy);//生成图,建立单向连接的表
        Root[tmpy]++;//在后边出现的表示其有被指向属性
    }
    for (int i = 1; i < n; i++)
    {
    
    
        if (Root[i] == 0)
        {
    
    //找根
            root = i;
        }
    }
    for (int i = 1; i <= n; i++)
    {
    
    //将每一个父节点的所有小节点进行排序
        sort(g[i].begin(), g[i].end());
    }

    if (points[root].flag == 1)
    {
    
    //此时为根节点需要排序的情况,即直接对所有数字排序即可
        sort(points + 1, points + n + 1, Rule());
        cout << "[" << points[1].num;
        for (int i = 2; i <= n; i++)
        {
    
    
            cout << "," << points[i].num;
        }
        cout << "]" << endl;
        return 0;
    }
    else
    {
    
    
        dfs(root);//从根节点开始搜索

        cout << "[" << v[root][0];
        for (int i = 1; i < v[root].size(); i++)
        {
    
    
            cout << "," << v[root][i];
        }
        cout << "]" << endl;
        return 0;
    }
}

猜你喜欢

转载自blog.csdn.net/zhj12399/article/details/109707518