CodeForces 681D Gifts by the List (树上DFS)

题意:一个家庭聚会,每个人都想送出礼物,送礼规则是, 一个人,先看名单列表,发现第一个祖先 就会送给他礼物,然后就不送了,如果他没找到礼物 他会伤心的离开聚会!告诉你m个祖先关系,

和每个人想给谁送!让你求出名单列表!

析:这个题,真是没想到啊,还是看的题解,首先要知道的是,如果自己和父结点送的人不一样,并且自己不是给自己的,那么就是无解,为什么呢?是这样的,假设自己和父结点送的人不一样,并且也不是给自己的,

那么一定是给自己的某个祖先,而父结点也是自己的某个祖先,那么不是同一个人,必定一个是另一个祖先,那么矛盾,所以一定是这样的,根据这个还不能确定出来结果,如果没人给自己送,那么这个结点就可以不要了,

在搜索时的有一个原则,用不到的就不要放上,更加简洁,也就是说,如果一个人不给自己送,那么这个人就没有存在的必要了,为什么呢?你想想,如果别人还给自己送了,自己又没给自己送,说明还有人是自己的祖先,

那么另一个人应该送和自己一样的人。对于搜索是先从祖先向下面进行搜索,然后判断能不能成立。

代码如下:

#include <bits/stdc++.h>

using namespace std;
const int maxn = 1e5 + 5;
vector<int> G[maxn],ans;
int a[maxn];
bool b[maxn];
bool ok;

void dfs(int u, int fa){
    for(int i = 0; i < G[u].size(); ++i){
        int v = G[u][i];
        if(v == fa)  continue;//判断是不是和父结点一样
        if(a[v] != a[u] && a[v] != v){  ok = true;  return ; }//矛盾,直接结束
        dfs(v, u);
    }
    if(a[u] == u)   ans.push_back(u);//如果不给自己送,那么就没有存在的必要了
}

int main(){
    int n, m, u, v;
    cin >> n >> m;
    while(m--){
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
        b[v] = true;//查找祖先
    }
    for(int i = 1; i <= n; ++i)  cin >> a[i];
    ok = false;
    for(int i = 1; i <= n; ++i)
        if(ok)  break;
        else if(!b[i])  dfs(i, -1);//搜索
    if(ok)  cout << "-1\n";
    else{
        cout << ans.size() << endl;
        for(int i = 0; i < ans.size(); ++i)
            cout << ans[i] << endl;
    }
    return 0;
}
时间: 2024-10-05 15:04:07

CodeForces 681D Gifts by the List (树上DFS)的相关文章

CodeForces 681D Gifts by the List

$dfs$,后续遍历. 如果某个节点$a[i]=i$,那么$i$的后继的$a[i]$都要指向$i$,直到出现新的后继$j$,$a[j]=j$.利用这个可以判断是否有解. 如果有解的话,那么只要输出后序遍历的结果就可以了. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include&

codeforces 455B A Lot of Games (Trie + dfs)

题目大意: 两个人往一个空的字符串里填单词,每一次只能填一个,而且填完之后要是给出的N个字符串的前缀. 思路分析: 先用给出的所有单词建字典树. 然后从根节点开始dfs. win [x] 表示踩在x节点上是否有必胜策略 lose [x] 表示踩在x节点上是否有必败策略. 然后是博弈的过程. 如果先手有必胜和必败的策略,那么他可以一直输到k-1 如果只有必胜策略.那么只有当k为奇数的时候它才能赢. 其他为后手赢. #include <cstdio> #include <iostream&g

Codeforces 982 C. Cut &#39;em all!(dfs)

解题思路: 代码中有详细注解,以任意一点为根,dfs遍历这棵树. 每一个节点可能有好几个子树,计算每棵子树含有的节点数,再+1即为这整棵树的节点. 判断子树是否能切断与根之间的联系,如果子树含有偶数个节点,则这棵子树可以被切断. 注意: 若由于我们建立这棵树的时候不知道两个连接的节点谁是谁的父节点. 所以我们在dfs中加个标记,找出除父节点以外的其他节点. #include <bits/stdc++.h> using namespace std; typedef long long ll; l

CodeForces 682C Alyona and the Tree (树上DFS)

题意:给定一棵树,每个叶子有一个权值,每条边也有一个权值,现在让你删最少的结点,使得从任何结点出发到另一个结点的边上权值和都小于两个结点的权值. 析:很明显是DFS,不过要想找出最少的结点可能不太容易,所以我们可以先找出剩下结点最多,那么用总数减去这个就好,那么怎么找哪些结点是剩下的呢?首先要知道,如果一个结点要被删掉, 那么它的子树肯定也要被删掉,并且,要满足dist(v, u) <= a[u]才是可能留下的,那么只要dist(v, u) >a[u],就不要,所以一定要注意的是,结点的距离可

Codeforces 776D:The Door Problem(DFS染色)

http://codeforces.com/problemset/problem/776/D 题意:有n个门,m个开关,每个门有一个当前的状态(0表示关闭,1表示打开),每个开关控制k个门,但是每个门确切的受两个开关控制,如果一个开关打开,那么原来关闭的门会打开,打开的门关闭,问是否存在一个情况使得所有的门打开. 思路:类似于01染色,把开关当成点,门当前的状态当成边权建图.初始先假设一个门的状态(初始假设为0和假设为1都是一样的,举几个例子就发现了),然后因为每个门受两个开关控制,所以可以推出

【Codeforces 723D】Lakes in Berland (dfs)

海洋包围的小岛,岛内的有湖,'.'代表水,'*'代表陆地,给出的n*m的地图里至少有k个湖,求填掉面积尽量少的水,使得湖的数量正好为k. dfs找出所有水联通块,判断一下是否是湖(海水区非湖).将湖按面积排序,若湖的数量为cnt,填掉前cnt-k个湖. http://codeforces.com/problemset/problem/723/D Examples input 5 4 1*****..*******.*..** output 1*****..*********..** input

570D Codeforces Round #316 (Div. 2) D(dfs序,时间戳,二分

题目:一棵树上每个节点有个字符值,询问每个节点的深度为h的子节点的字符是否能组成一个回文串. 思路:首先是奇妙的dfs序和时间戳,通过记录每个节点的dfs进出时间,可以发现某个节点的子节点的进出时间均在该节点的进出时间范围内(这是很直观的dfs的性质),这样可以把树形结构转变为线性结构,方便进行各种处理.dfs一遍处理时间戳,每个节点的深度,并记录每个深度的节点都有哪些,此时每个深度的节点就是排好序的.然后对于一个询问,可以利用二分查找确定子节点在该层的哪一段.对于每一层,预先处理每个字符的前缀

hihocoder 1192 简单的树嵌入 (树上DFS 构造 好题)

#1192 : 简单的树嵌入 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一棵n个点的无权树.定义两点i,?j(0?≤?i,?j?≤?n?-?1)间的距离d(i,?j)为两点间树上最短路径的长度(边数). 我们需要将这n个点映射到中的向量v0?=?(v0,?0,?...,?v0,?m?-?1),?...,?vn?-?1?=?(vn?-?1,?0,?...,?vn?-?1,?m?-?1).定义两向量vi,?vj间的L1距离为 我们希望对于所有0?≤?i,?j?

CodeForces 690C2 Brain Network (medium)(树上DP)

题意:给定一棵树中,让你计算它的直径,也就是两点间的最大距离. 析:就是一个树上DP,用两次BFS或都一次DFS就可以搞定.但两次的时间是一样的. 代码如下: #include<bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; vector<int> G[maxn]; int f[maxn], g[maxn], l[maxn]; int dfs(int root, int fa){ if(f[root] !=