dfs序:

每个节点在dfs中的进出栈的时间序列。

树是非线性结构,根节点连着子节点,那么dfs序...节点进出栈的时间先后?

从根节点入栈,然后左儿子入栈,左儿子出栈,右儿子入栈,右儿子出栈,根节点出栈。

某节点的儿子在序列中的位置大于该节点入栈的位置小于该节点出栈的位置

这样就将一棵树变成了一个区间问题

(从某个节点入栈到某个节点出栈之间的节点都是该节点的子树??)

例:

1 2 3 3 2 1

1的左儿子为2,2的左儿子为3

1 2 2 3 3 1

1的左儿子为2,右儿子为3

(图片来源于网络)

比如这棵树,我们用dfs来搞一遍

那么这个树的dfs序就是

其中每个节点都出现了两次,一次是进入dfs的时刻,第二次是离开dfs的时刻,分别称之为In与Out。在区间操作中,如果某个节点出现了2次,则该节点将被“抵消”。所以通常会将Out时刻对应的点设置为负数。

性质:

现在来介绍dfs序列一些有用的性质:

任意子树都是连续的。例如假设有个子树BEFK,在序列中对应的部分是:BEEFKKFB;子树CGHI,在序列中对应的部分是:CGGHHIIC。

任意点对(a,b)之间的路径,可分为两种情况,首先是令lca是a、b的最近公共祖先:

1.若lca是a、b之一,则a、b之间的in时刻的区间或者out时刻区间就是其路径。例如AK之间的路径就对应区间ABEEFK或者KFBCGGHHIICA。

2.若lca另有其人,则a、b之间的路径为In[a]、Out[b]之间的区间或者In[b]、Out[a]之间的区间。另外,还需额外加上lca!!!考虑EK路径,对应为EFK再加上B。考虑EH之间的路径,对应为EFKKFBCGGH再加上A。

利用这些性质,可以利用DFS序列完成子树操作和路径操作。据传说还有更强大的使用方法,然而我还不会就是

#include<bits/stdc++.h>

#define maxn 100076

using namespace std;

struct treedfs{

int y, next;

}e[maxn];

int lin[maxn];

int tree_dfs[maxn], top = 0;

int in[maxn], out[maxn];

int n, len = 0;

bool flag[maxn];

inline void add (int x, int y){

e[++len].y = y;

e[len].next = lin[x];

lin[x] = len;

}

void dfs (int c) {

tree_dfs[++top] = c;

in[c] = top;

flag[c] = 1;

for (int i = lin[c]; i ;i = e[i].next) {

int to = e[i].y;

if(!flag[to])

dfs(to);

}

tree_dfs[++top] = c;

out[c] = top;

}

int main() {

memset(flag, 0, sizeof(flag));

scanf("%d", &n);

for (int i = 1;i <= n-1; i++) {

int x, y;

scanf("%d%d", &x, &y);

add(x, y);

add(y, x);

}

dfs(1);

for(int i = 1; i <= top; i++)

cout << tree_dfs[i] << ' ';

cout << endl;

for(int i = 1; i <= n; i++)

cout << in[i] << ' ' << out[i] << endl;

return 0;

}

Emmmm这大概就是dfs序的基础代码,输出一棵树的dfs序。

哦天哪,看看这丑陋的代码(捂脸)……

事实上我们也完全可以只记录dfs过程中被搜索到的顺序的先后。

void dfs(int c){

id[++top] = c;

in[c] = top;

f[c] = 1;

for(int i = lin[c]; i ; i = e[i].next){

int to = e[i].y;

if(!f[to])

dfs(to);

}

out[c] = top;

}

在这里id数组记录的就是这个树实际进行dfs的搜索顺序的先后

注:这里in和out记录的位置是不同的

这里in记录的确实按照只记录每个节点的被搜索的先后的方式记录的,out记录的则是以in中记录的那个节点的所有子树的终止位置,这么说可能不太清楚,举个例子

一棵树的关系是这样的:每行为x和y,表示x是y的父亲

1  4

5  4

1  3

2  4

对于这么一棵树,按照以上代码得到的dfs序为:

1  3  4  2  5

而在in和out中记录的分别是:

1         5

2         2

3         5

4         4

5         5

也就是说:

1是根节点,所以1的子树有子树就有3和4 2 5,out中1的结束下标就是5

3没有子树,他在out中的记录的位置和在in中是一样的

以此类推。

那么这个操作有什么用呢?emmmm我也不知道有什么用。

反正他应该和我们最初讨论的是一样的,都是把树变成区间然后用线段树进行操作

拿道具体题看看

Jzoj的艰难的回寝之路,原题是usaco的慢下来。

思路非常明显,dfs序+线段树就可以简单a掉了

代码:

#include<bits/stdc++.h>

#define maxn 500086

using namespace std;

struct node{

int y, next;

}e[maxn];

int tree[maxn];

int lin[maxn];

int n, len = 0, top = 0;

int in[maxn], out[maxn], id[maxn];

bool f[maxn];

inline int read(){

int x = 0;

char ch = getchar();

while(ch < '0' || ch > '9')

ch = getchar();

while(ch >= '0' && ch <= '9'){

x = x * 10 + ch - '0';

ch = getchar();

}

return x;

}

inline void add(int x, int y){

e[++len].y = y;

e[len].next = lin[x];

lin[x] = len;

}

void dfs(int c){

id[++top] = c;

in[c] = top;

f[c] = 1;

for(int i = lin[c]; i ; i = e[i].next){

int to = e[i].y;

if(!f[to])

dfs(to);

}

out[c] = top;

}

inline void pushdown(int pos){

if(!tree[pos]) return;

int lc = pos << 1, rc = pos << 1 | 1, v = tree[pos];

tree[lc] += v;

tree[rc] += v;

tree[pos] = 0;

}

void update(int pos,int L,int R,int l,int r){

if(l > R || r < L) return;

if(l >= L && r <= R){

tree[pos]++;

return ;

}

pushdown(pos);

int m= l + r >> 1;

update(pos << 1, L, R, l, m);

update(pos << 1 | 1, L, R, m+1, r);

}

int query(int pos,int aim,int l,int r){

if(l == r)return tree[pos];

pushdown(pos);

int m = l + r >> 1;

if(aim <= m) return query(pos << 1, aim, l, m);

else return query(pos << 1 | 1, aim, m+1, r);

}

int main(){

memset(f, 0, sizeof(f));

cin>>n;

for(int i=1;i<=n-1;i++){

int x, y;

x = read(); y = read();

add(x, y);

add(y, x);

}

dfs(1);

for(int i = 1; i <= n; i++){

int k;

k = read();

cout<<query(1, in[k], 1, n)<<endl;

update(1, in[k] + 1, out[k], 1, n);

}

return 0;

}

dfs序学习总结的更多相关文章

  1. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

  2. 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)

    http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...

  3. 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...

  4. dfs序和欧拉序

    生命不息,学习不止,昨天学了两个算法,总结一下,然而只是略懂,请路过的大佬多多谅解.   一.dfs序 1.什么是dfs序? 其实完全可以从字面意义上理解,dfs序就是指一棵树被dfs时所经过的节点的 ...

  5. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

  6. 【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解

        这一题是对AC自动机的充分理解和树dfs序的巧妙运用. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和' ...

  7. Codeforces - 570D 离散DFS序 特殊的子树统计 (暴力出奇迹)

    题意:给定一棵树,树上每个节点有对应的字符,多次询问在\(u\)子树的深度为\(d\)的所有节点上的字符任意组合能否凑成一个回文串 把dfs序存储在一个二维线性表中,一个维度记录字符另一个维度记录深度 ...

  8. 浅谈DFS序

    浅谈DFS序 本篇随笔简要讲解一下信息学奥林匹克竞赛中有关树的DFS序的相关内容. DFS序的概念 先来上张图: 树的DFS序,简单来讲就是对树从根开始进行深搜,按搜到的时间顺序把所有节点打上时间戳. ...

  9. dfs序+RMQ求LCA详解

    首先安利自己倍增求LCA的博客,前置(算不上)知识在此. LCA有3种求法:倍增求lca(上面qwq),树链剖分求lca(什么时候会了树链剖分再说.),还有,标题. 是的你也来和我一起学习这个了qwq ...

随机推荐

  1. Notice : brew install php70

    To enable PHP in Apache add the following to httpd.conf and restart Apache: LoadModule php7_module  ...

  2. [Leetcode] Same tree判断是否为相同树

    Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...

  3. BZOJ1558 [JSOI2009]等差数列 【线段树】

    题目链接 BZOJ1558 题解 等差数列,当然是差分一下 差分值相同的连续位置形成等差数列,我们所选的两个等差数列之间可以有一个位置舍弃 例如: \(1 \; 2 \; 3 \; 6 \; 8 \; ...

  4. [bzoj1033] [ZJOI2008]杀蚂蚁 Big MoNI

    这个模拟就不用说了吧...... 注意事项(救命的):1.不能回原位 2.在可以打到target的塔打target的时候,其他打不到的继续打自己的(这是显然的事情只是当时已惘然) 3.如果游戏在某一秒 ...

  5. NEYC 2017 自动取款机 atm Day6 T1

                                                                                          自动取款机 [问题描述] 小 ...

  6. NAS星云链 入门之从零开发第一个DAPP

    应该有很多小伙伴和我一样,一直想去入手学习区块链,但是总无从下手,有些概念感觉理解了,有感觉没理解.其实这都是“没实践”的锅. 所谓看十遍不如想一遍,想一遍不如做一遍.这不最近星云链nebulas正有 ...

  7. 如何使用Photoshop制作真实的尺子

    前言: 日常生活中经常性的偶尔需要测量一些东西的尺寸,但刚好手头上缺乏尺子等必要的测量工具,这时候其实我们可以利用Photoshop,临时制作一把基于现实物理单位(如:厘米)的虚拟尺子. 难点: 像素 ...

  8. 动态性能视图v$session_longops

    v$session_longops This view displays the status of various operations that run for longer than 6 sec ...

  9. es6+最佳入门实践(9)

    9.Iterator和for...of 9.1.Iterator是什么? Iterator又叫做迭代器,它是一种接口,为各种不同的数据结构提供统一的访问机制.这里说的接口可以形象的理解为USB接口,有 ...

  10. MyEclipse中代码提醒功能

    一:最近仔细研究了下spring mvc中的代码,自己在配置文件哪里来时出现问题,没有提醒,只好自己搜了下有关的信息.如下 window--->preferences---->java-- ...