dfs序学习总结
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序学习总结的更多相关文章
- Educational Codeforces Round 6 E dfs序+线段树
题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...
- 【SPOJ】10628. Count on a tree(lca+主席树+dfs序)
http://www.spoj.com/problems/COT/ (速度很快,排到了rank6) 这题让我明白了人生T_T 我知道我为什么那么sb了. 调试一早上都在想人生. 唉. 太弱. 太弱. ...
- 【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)
http://www.lydsy.com/JudgeOnline/problem.php?id=1146 第一种做法(时间太感人): 第二种做法(rank5,好开心) ================ ...
- dfs序和欧拉序
生命不息,学习不止,昨天学了两个算法,总结一下,然而只是略懂,请路过的大佬多多谅解. 一.dfs序 1.什么是dfs序? 其实完全可以从字面意义上理解,dfs序就是指一棵树被dfs时所经过的节点的 ...
- BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树
题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...
- 【AC自动机】【树状数组】【dfs序】洛谷 P2414 [NOI2011]阿狸的打字机 题解
这一题是对AC自动机的充分理解和树dfs序的巧妙运用. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和' ...
- Codeforces - 570D 离散DFS序 特殊的子树统计 (暴力出奇迹)
题意:给定一棵树,树上每个节点有对应的字符,多次询问在\(u\)子树的深度为\(d\)的所有节点上的字符任意组合能否凑成一个回文串 把dfs序存储在一个二维线性表中,一个维度记录字符另一个维度记录深度 ...
- 浅谈DFS序
浅谈DFS序 本篇随笔简要讲解一下信息学奥林匹克竞赛中有关树的DFS序的相关内容. DFS序的概念 先来上张图: 树的DFS序,简单来讲就是对树从根开始进行深搜,按搜到的时间顺序把所有节点打上时间戳. ...
- dfs序+RMQ求LCA详解
首先安利自己倍增求LCA的博客,前置(算不上)知识在此. LCA有3种求法:倍增求lca(上面qwq),树链剖分求lca(什么时候会了树链剖分再说.),还有,标题. 是的你也来和我一起学习这个了qwq ...
随机推荐
- 【题解】ZJOI2007报表统计
洛谷传送门 主要思路大概也是差不多的,对于两种询问分别用线段树与平衡树来维护. 1.MIN_SORT_GAP:显然平衡树简单操作,来一发前驱.后继即可. 2.MIN_GAP:这一个我用的是线段树:可以 ...
- Linux总结(二)
1. 虚拟机安装 a)双系统(不建议初学者一开始去装) b)般建议使用虚拟机来操作试验环境 c)好处:可以模拟真实的环境进行各种的试验和操作 d)在启动之后,在操作的时候会占用一部分的系统资源 1 ...
- BZOJ4785 [Zjoi2017]树状数组 【二维线段树 + 标记永久化】
题目链接 BZOJ4785 题解 肝了一个下午QAQ没写过二维线段树还是很难受 首先题目中的树状数组实际维护的是后缀和,这一点凭分析或经验或手模观察可以得出 在\(\mod 2\)意义下,我们实际求出 ...
- init_connect基本用法
服务器为每个连接的客户端执行的字符串.字符串由一个或多个SQL语句组成.要想指定多个语句,用分号间隔开.例如,每个客户端开始时默认启用autocommit模式.没有全局服务器变量可以规定autocom ...
- 【可持久化线段树?!】rope史上最全详解
https://www.luogu.org/problemnew/show/P3919 看到上面链接中的题时,我在学会可持久化线段树的同时,第一次学会了一个非常屌(cai)的STL大法——rope!! ...
- SICAU-OJ:要我唱几首歌才能够将你捕捉
要我唱几首歌才能够将你捕捉 题意: 有N种颜色的牛,现在可以执行以下两种操作: 1.抓捕一只牛,代价为ai: 2.花费x的代价使用魔法,让所有颜色加1,N会变为1. 求得到N种颜色的牛最少花费的代价. ...
- Educational Codeforces Round 55 (Rated for Div. 2):E. Increasing Frequency
E. Increasing Frequency 题目链接:https://codeforces.com/contest/1082/problem/E 题意: 给出n个数以及一个c,现在可以对一个区间上 ...
- JS模块化工具requirejs教程01
转自:http://www.runoob.com/w3cnote/requirejs-tutorial-1.html 随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签 ...
- Nginx各项配置的含义
#user nobody; #配置用户或者组,默认为nobody nobody worker_processes 4; #允许生成的进程数,默认为1 worker_cpu_affinity 00000 ...
- 复选框回显、全选、非全选、cookie处理数据、json数组对象转换处理学习笔记参考的页面
<%@include file="/common/head.jsp"%> <%@ page contentType="text/html; charse ...