首页 > 其他分享 >[题解] CF29D Ant on the Tree

[题解] CF29D Ant on the Tree

时间:2023-09-09 12:55:45浏览次数:38  
标签:std int 题解 Tree Ant dep ls auto now

CF29D Ant on the Tree

题目知识点:LCA。

题目传送门

题意

给定一棵以 \(1\) 为节点的树,再给定树的所有叶子节点的一个序列。

现在执行一个操作:从 \(1\) 开始遍历每个节点,并返回根,要求每条边经过的次数一定为 \(2\) 。

问是否能够使得访问节点序列中叶子节点的序列符合给定序列的条件下,满足上述操作的条件。

思路

我们暂时不考虑每条边经过次数一定为 \(2\) 的这个要求,先看我们一定要经过的点。

  • 对于给定序列的第一个和最后一个,由于要求需要从根节点出发和回到根节点,因此,这两个的路径有一端点是根节点;
  • 对于序列中的 \(v_i\) 和 \(v_{i+1}\) 节点,由于树的特性,其路径一定为 \(v_i \to lca(v_i, v_{i+1}) \to v_{i+1}\) 。

这样,我们可以确定在满足序列的条件下,有且只有一种走法。

若出现不满足的条件,我们需要判断一下这个唯一的走法是否对于树上每条边都是走了 \(2\) 次,只需要对路径记录一下每条边访问的次数,最后检查一下即可。

实现

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

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);

    int n;
    std::cin >> n;

    std::vector adj(n, std::vector<std::pair<int,int>>{});
    for (int i = 0; i < n - 1; i ++) {
        int u, v;
        std::cin >> u >> v;
        u --; v --;
        adj[u].emplace_back(v, i);
        adj[v].emplace_back(u, i);
    }

    std::vector<int> dep(n, -1), fa(dep), top(dep), siz(dep), son(dep), fa_eid(dep);
    int m = 0;
    auto dfs1 = [&](auto &self, int from, int come_eid) -> void {
        siz[from] = 1;
        son[from] = -1;
        bool have_vis = false;
        for (auto [to, eid] : adj[from]) {
            if (dep[to] == -1) {
                have_vis = true;
                dep[to] = dep[from] + 1;
                fa[to] = from;
                fa_eid[to] = eid;
                self(self, to, eid);
                siz[from] += siz[to];
                if (son[from] == -1 || siz[to] > siz[son[from]]) {
                    son[from] = to;
                }
            }
        }
        m += !have_vis;
    };
    auto dfs2 = [&](auto &self, int from, int link_top) -> void {
        top[from] = link_top;
        if (son[from] == -1) return;
        self(self, son[from], link_top);
        for (auto [to, eid] : adj[from]) {
            if (to != son[from] && to != fa[from]) {
                self(self, to, to);
            }
        }
    };
    dep[0] = 0;
    dfs1(dfs1, 0, -1);
    dfs2(dfs2, 0, 0);

    auto GetLca = [&](int a, int b) -> int {
        while (top[a] != top[b]) {
            if (dep[top[a]] < dep[top[b]]) {
                std::swap(a, b);
            }
            a = fa[top[a]];
        }
        if (dep[a] > dep[b]) {
            std::swap(a, b);
        }
        return a;
    };

    std::vector<int> vis_cnt(n - 1);
    std::vector<int> ans;
   
    std::vector<int> ls(m);
    for (auto &item : ls) {
        std::cin >> item;
        item --;
    }

    std::vector<int> tmp;
    auto GetList = [&](auto &list, int now, int tag) {
        list.clear();
        do {
            list.emplace_back(now);
            if (fa_eid[now] != -1) vis_cnt[fa_eid[now]] ++;
            now = fa[now];
        } while (now != tag);
        list.emplace_back(tag);
   };
    GetList(tmp, ls.front(), 0);

    auto AddList = [&](auto &ret, auto &ls, bool rev) {
        if (rev) std::reverse(ls.begin(), ls.end());
        while (!ls.empty()) {
            ret.emplace_back(ls.back());
            ls.pop_back();
        }
    };
    AddList(ans, tmp, false);

    for (int i = 1; i < ls.size(); i ++) {
        int pre = ls[i - 1], now = ls[i];
        auto lca = GetLca(pre, now);
        GetList(tmp, pre, lca);
        AddList(ans, tmp, true);
        GetList(tmp, now, lca);
        AddList(ans, tmp, false);
    }
    GetList(tmp, ls.back(), 0);
    AddList(ans, tmp, true);

    if (!all_of(vis_cnt.begin(), vis_cnt.end(), [](auto item) { return item == 2; })) {
        std::cout << -1 << '\n';
    } else {
        ans.erase(std::unique(ans.begin(), ans.end()), ans.end());
        for (auto item : ans) {
            std::cout << item + 1 << ' ';
        }
        std::cout << '\n';
    }
}

标签:std,int,题解,Tree,Ant,dep,ls,auto,now
From: https://www.cnblogs.com/FlandreScarlet/p/17689317.html

相关文章

  • Semantic Kernel
    https://github.com/microsoft/semantic-kernelSemanticKernel isanSDKthatintegratesLargeLanguageModels(LLMs)like OpenAI, AzureOpenAI,and HuggingFace withconventionalprogramminglanguageslikeC#,Python,andJava.SemanticKernelachievesth......
  • P2206题解
    题目大意:给定一些指令,计算需要多大的舞台。这是一道大模拟!!!只要遍历每次指令,然后判断是否摔倒,摔倒输出`-1`否则记录,最后求出面积就行了。最后附上代码1#include<bits/stdc++.h>2usingnamespacestd;3constintxx[]={-1,0,1,0},yy[]={0,1,0,-1};//不同......
  • CF1513C题解
    一道递推由于对于一个数x,可得x+10-x=10(废话)于是问题就变成了0+m次,然后x+m就变成0+x+m(还是废话)于是可以写一个递推。首先对于函数f(m)可分为m ≤9和m>9,然后可得出递推式结果为1或f(m-9)+f(m-10),所以我们可以直接求出结果再分解数位求值。最后贴上代码......
  • P2203题解
    题意给定一个环形01序列,每次变化时,对于每个位置,如果前一个值是1,则当前值翻转。求变化B次后的序列。思路由于B的值很大,所以如果对每一次变化进行模拟,效率非常低下。不难发现,每一次变化后的状态完全是由当前状态决定的,而N的范围很小,所以可能的状态总数2^N也不是很大......
  • CF812B题解
    康了康唯一的题解,说没必要用DP,我就给出DP的解法。这其实是道水题,唯一的坑是有可能楼上没有开的灯,坑了我们机房的一堆人(WAontest4),剩下的就是DP。我们用a[n][0],表示第n层的第一个房间,用a[n][1],表示第n层的最后一个房间。这里提供一个收集型的写法。所以可得状态转移......
  • CF1690E题解
    ##主要题意:有$n$个礼物,要两两合并,然后除以$k$最后求和最大。##思路:先加入每个数除以$k$的商(单独组成$k$的个数),然后全部$\bmod\k$存入数组,排序,最后双指针一个前一个后求两个余数可以大于等于$k$的两个礼物。##代码:```cpp#include<bits/stdc++.h>usingname......
  • CF1690C题解
    ##主要题意:>有$n$个任务,必须在$s_i$到$t_i$之间完成,求每个任务最大可以完成多久(优先前面的最大)。##思路>就拿一个变量记录当前时间,然后贪心选择$a[i].t$和$a[i+1].t$中的最小值,(应为至少也要给下一个任务留$1$的时间),最后做减法,输出即可。##代码>```cpp>#incl......
  • 9-9|tree如何实现ll的效果
    `tree`命令是用于递归地列出目录和子目录的工具。而`ll`是`ls-l`的常见别名,用于长格式列出文件和目录。要使用`tree`来模拟`ll`(即`ls-l`)的效果,您需要:1.只列出当前目录。2.显示文件和目录的详细信息。您可以使用以下`tree`参数组合来达到这个效果:```bashtree......
  • pytest运行警告问题解决:DeprecationWarning: pkg_resources is deprecated as an API
    前言最近在运行pytest的时候,经常出现这个警告DeprecationWarning:pkg_resourcesisdeprecatedasanAPISeehttps://setuptools.pypa.io/en/latest/pkg_resources.htmlfrompkg_resourcesimportiter_entry_points从警告上看是方法被弃用,肯定是因为新版弃用了旧版的语法。......
  • luogu P1419 题解
    题目链接description给定一个长度为\(n\)的序列(值域为\([-10^4,10^4]\))和正整数\(st,ed\)。求一个区间,使得其长度\(\in[st,ed]\)且平均值最大,输出平均值。\(1\leqn\leq10^5\)solution这里给出一个复杂度线性的做法。求出前缀和数组\(s\),答案相当于\(\max\limit......