部分参考自博客:https://blog.csdn.net/hpu2022/article/details/81910490

在许多问题中,由于树结构复杂通常会导致问题很棘手,因为其实非线性结构,操作起来也甚是费时。

例如:对于一棵树,含有n个节点,每个节点拥有相应的权值,我们进行很多个操作,比如可以修改某个节点的权值,查找以某个节点为根节点的子树和。

显然,对于这个问题,每次计算子树权值和时我们都要遍历一下各个节点,而如果我们可以用某种方式把它装化成线性结构,然后再用数组数组或者线段树去更新查询,这样不就可以更高效得多吗?

没错,这就有了我们DFS序,它的主要思路就是将树形结构转化成线性结构,用dfs遍历一遍这棵树,进入到x节点有一个in时间戳,递归退出时有一个out 时间戳,x节点的两个时间戳之间遍历到的点,就是根为x的子树的所有节点,他们的dfs进入时间戳是递增的。同时两个时间戳构成了一个区间,x节点在这段区间的最左端,这个区间就是一棵根节点为x的子树,对于区间的操作就是其他维护方式的应用了。

int time = ;
inline void dfs(int x, int fa) {
in[x] = ++time; //进入的时间戳
num[time] = x; //生成新的线性结构
for(int i = ; i < G[x].size(); i++) {
int cnt = G[x][i];
if(cnt == fa) continue;
dfs(cnt, x);
}
out[x] = time; //出去的时间戳
}

in[x]表示映射的DFS预处理出的线性结构,也就是说x是原始节点,in[x]是x节点的新位置,num[t]表示第t个节点的编号,num[in[x]]表示的还是x。num是新序列,in表示是新序列的下标,in[x]~out[x]是x为根结点的子树,划分为一个区间。

Loj144 DFS序+树状数组单点更新区间查找

题目链接:https://loj.ac/problem/144

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
const ll maxn=1e6+;
int n,q,m,r,tot,cnt;
ll v[maxn],in[maxn],out[maxn],head[maxn],x,num[maxn],sum[maxn];
struct node{
int to,next;
}edge[*maxn];
void add(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int pos,int fa){
num[++cnt]=pos;
in[pos]=cnt;
for(int i=head[pos];i!=-;i=edge[i].next){
int v=edge[i].to;
if(v!=fa) dfs(v,pos);
}
out[pos]=cnt;
}
int lowbit(int x){
return x&(-x);
}
void update(int x,int y){
while(x<=n){
sum[x]+=y;
x+=lowbit(x);
}
}
ll ask(int x){
ll res=;
while(x){
res+=sum[x];
x-=lowbit(x);
}
return res;
}
int main(){
scanf("%d%d%d",&n,&m,&r);
for(int i=;i<=n;i++)
scanf("%lld",&v[i]),head[i]=-;
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs(r,-);
for(int i=;i<=n;i++)
update(in[i],v[i]);
while(m--){
int op,x,y;
scanf("%d",&op);
if(op==){
scanf("%d%d",&x,&y);
update(in[x],y);
}
else{
scanf("%d",&x);
printf("%lld\n",ask(out[x])-ask(in[x]-));
}
}
return ;
}

Loj 145 DFS序+树状数组区间更新区间查找

题目链接:https://loj.ac/problem/145

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
const ll maxn=1e6+;
int n,q,m,r,tot,cnt;
ll v[maxn],in[maxn],out[maxn],head[maxn],x,num[maxn],sum1[maxn],sum2[maxn];
struct node{
int to,next;
}edge[*maxn];
void add(int u,int v){
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void dfs(int pos,int fa){
num[++cnt]=pos;
in[pos]=cnt;
for(int i=head[pos];i!=-;i=edge[i].next){
int v=edge[i].to;
if(v!=fa) dfs(v,pos);
}
out[pos]=cnt;
}
int lowbit(int x){return x&(-x);}
void update(int x,ll y){
for(int i=x;i<=n;i+=lowbit(i)){
sum1[i]+=y;
sum2[i]+=(x-)*y;
}
}
ll ask(int x){
ll res=;
for(int i=x;i;i-=lowbit(i)){
res+=x*sum1[i]-sum2[i];
}
return res;
}
int main(){
scanf("%d%d%d",&n,&m,&r);
for(int i=;i<=n;i++)
scanf("%lld",&v[i]),head[i]=-;
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
add(u,v); add(v,u);
}
dfs(r,-);
for(int i=;i<=n;i++)
update(in[i],v[i]-v[num[in[i]-]]);
while(m--){
int op,x,y;
scanf("%d",&op);
if(op==){
scanf("%d%d",&x,&y);
update(in[x],y); update(out[x]+,-y);
}
else{
scanf("%d",&x);
printf("%lld\n",ask(out[x])-ask(in[x]-));
}
}
return ;
}

Libre OJ 144、145 (DFS序)的更多相关文章

  1. Comet OJ - Contest #11 D isaster 重构树+倍增+dfs序+线段树

    发现对于任意一条边,起决定性作用的是节点编号更大的点. 于是,对于每一条边,按照节点编号较大值作为边权,按照最小生成树的方式插入即可. 最后用线段树维护 dfs 序做一个区间查询即可. Code: # ...

  2. BZOJ_4034 [HAOI2015]树上操作 【树链剖分dfs序+线段树】

    一 题目 [HAOI2015]树上操作 二 分析 树链剖分的题,这里主要用到了$dfs$序,这题比较简单的就是不用求$lca$. 1.和树链剖分一样,先用邻接链表建双向图. 2.跑两遍$dfs$,其实 ...

  3. DFS序和7种模型

    DFS序就是将树的节点按照先根的顺序遍历得到的节点顺序 性质:一个子树全在一个连续的区间内,可以与线段树和树状数组搭配使用 很好写,只需在dfs中加几行代码即可. 代码: void dfs(ll u, ...

  4. BZOJ 3083: 遥远的国度 [树链剖分 DFS序 LCA]

    3083: 遥远的国度 Time Limit: 10 Sec  Memory Limit: 1280 MBSubmit: 3127  Solved: 795[Submit][Status][Discu ...

  5. BZOJ 4196: [Noi2015]软件包管理器 [树链剖分 DFS序]

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1352  Solved: 780[Submit][Stat ...

  6. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  7. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

  8. 【BZOJ-1146】网络管理Network DFS序 + 带修主席树

    1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3495  Solved: 1032[Submi ...

  9. 【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

    E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard inpu ...

随机推荐

  1. LLDB 3.9.1 安装方法

    1. baidu到一个安装方法 进行尝试: 来源: https://zhuanlan.zhihu.com/p/40780819https://www.jianshu.com/p/f965bbba6eb ...

  2. php 生成订单号201807205598981

    php版 /** * 生成唯一订单号 */ public function build_order_no() { $no = date('Ymd').substr(implode(NULL, arra ...

  3. day 7-13 数据库的数据类型

    一. 数据类型 存储引擎决定了表的类型,而表内存放的数据也要有不同的类型,每种数据类型都有自己的宽度,但宽度是可选的 注意:int类型的宽度是显示宽度,并非是数据的存储宽度 详细的介绍:http:// ...

  4. websocket协议握手详解

    最近使用tornado做长链接想着怎么着也要试试websocket协议吧.所以说干就干. 首先要知道websocket是基于http协议的,为什么这么说?因为从协议来说,websocket是借用了一部 ...

  5. HTML5 & tel & make a phone call

    HTML5 & tel & make a phone call 咋呼叫呀,网页怎么打电话? { key: "exploreCorpPhone", title: &q ...

  6. vue实例相关

    第一种方法要比第二种更省事 if (!row.alert_at) return; if(row.alert_at){ } else { } v-for="todo in list" ...

  7. CSAW 2016:Rock-100

    ELF文件 拖进ida 震惊: 这一堆堆都是什么神仙函数呀!! f5看一下伪代码 可以看出来 其实看起来函数很多 但是真正管用的函数也就那么几个 如果sub_4017E6的值是0 那么就会输出flag ...

  8. bzoj2762-[JLOI2011]不等式组

    求 \(x=k\) 时满足一元一次不等式 \(ax+b<c\) 的个数. 解出 \(\frac{c-b}{a}\) 之后取整,得到合法区间,用树状数组维护. 注意 \(a\) 的值域是 \([- ...

  9. sql server对已创建的表增加属性(自动增序)

    新建此表时把ID设为INT类型,然后设Identity为yes,种子为1递增就可以了.如果这张表已经建了,你在最后加一个字段叫ID,然后和上面一样操作,然后保存即可自增.(一定要设置完在保存) alt ...

  10. RPM包定制

    概述 问题:当领导给你 100 台已经安装好系统的服务器,然后让优化,让你提出一个快速部署方案.解答: 1.tar 打包 先编译安装 打包-->分发-->解包(比如 mysql 打包后直接 ...