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

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

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

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

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

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

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

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7. #define lson l,mid,rt<<1
  8. #define rson mid+1,r,rt<<1|1
  9. typedef long long ll;
  10. const ll maxn=1e6+;
  11. int n,q,m,r,tot,cnt;
  12. ll v[maxn],in[maxn],out[maxn],head[maxn],x,num[maxn],sum[maxn];
  13. struct node{
  14. int to,next;
  15. }edge[*maxn];
  16. void add(int u,int v){
  17. edge[tot].to=v;
  18. edge[tot].next=head[u];
  19. head[u]=tot++;
  20. }
  21. void dfs(int pos,int fa){
  22. num[++cnt]=pos;
  23. in[pos]=cnt;
  24. for(int i=head[pos];i!=-;i=edge[i].next){
  25. int v=edge[i].to;
  26. if(v!=fa) dfs(v,pos);
  27. }
  28. out[pos]=cnt;
  29. }
  30. int lowbit(int x){
  31. return x&(-x);
  32. }
  33. void update(int x,int y){
  34. while(x<=n){
  35. sum[x]+=y;
  36. x+=lowbit(x);
  37. }
  38. }
  39. ll ask(int x){
  40. ll res=;
  41. while(x){
  42. res+=sum[x];
  43. x-=lowbit(x);
  44. }
  45. return res;
  46. }
  47. int main(){
  48. scanf("%d%d%d",&n,&m,&r);
  49. for(int i=;i<=n;i++)
  50. scanf("%lld",&v[i]),head[i]=-;
  51. for(int i=;i<n;i++){
  52. int u,v;
  53. scanf("%d%d",&u,&v);
  54. add(u,v); add(v,u);
  55. }
  56. dfs(r,-);
  57. for(int i=;i<=n;i++)
  58. update(in[i],v[i]);
  59. while(m--){
  60. int op,x,y;
  61. scanf("%d",&op);
  62. if(op==){
  63. scanf("%d%d",&x,&y);
  64. update(in[x],y);
  65. }
  66. else{
  67. scanf("%d",&x);
  68. printf("%lld\n",ask(out[x])-ask(in[x]-));
  69. }
  70. }
  71. return ;
  72. }

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

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

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<cmath>
  6. using namespace std;
  7. #define lson l,mid,rt<<1
  8. #define rson mid+1,r,rt<<1|1
  9. typedef long long ll;
  10. const ll maxn=1e6+;
  11. int n,q,m,r,tot,cnt;
  12. ll v[maxn],in[maxn],out[maxn],head[maxn],x,num[maxn],sum1[maxn],sum2[maxn];
  13. struct node{
  14. int to,next;
  15. }edge[*maxn];
  16. void add(int u,int v){
  17. edge[tot].to=v;
  18. edge[tot].next=head[u];
  19. head[u]=tot++;
  20. }
  21. void dfs(int pos,int fa){
  22. num[++cnt]=pos;
  23. in[pos]=cnt;
  24. for(int i=head[pos];i!=-;i=edge[i].next){
  25. int v=edge[i].to;
  26. if(v!=fa) dfs(v,pos);
  27. }
  28. out[pos]=cnt;
  29. }
  30. int lowbit(int x){return x&(-x);}
  31. void update(int x,ll y){
  32. for(int i=x;i<=n;i+=lowbit(i)){
  33. sum1[i]+=y;
  34. sum2[i]+=(x-)*y;
  35. }
  36. }
  37. ll ask(int x){
  38. ll res=;
  39. for(int i=x;i;i-=lowbit(i)){
  40. res+=x*sum1[i]-sum2[i];
  41. }
  42. return res;
  43. }
  44. int main(){
  45. scanf("%d%d%d",&n,&m,&r);
  46. for(int i=;i<=n;i++)
  47. scanf("%lld",&v[i]),head[i]=-;
  48. for(int i=;i<n;i++){
  49. int u,v;
  50. scanf("%d%d",&u,&v);
  51. add(u,v); add(v,u);
  52. }
  53. dfs(r,-);
  54. for(int i=;i<=n;i++)
  55. update(in[i],v[i]-v[num[in[i]-]]);
  56. while(m--){
  57. int op,x,y;
  58. scanf("%d",&op);
  59. if(op==){
  60. scanf("%d%d",&x,&y);
  61. update(in[x],y); update(out[x]+,-y);
  62. }
  63. else{
  64. scanf("%d",&x);
  65. printf("%lld\n",ask(out[x])-ask(in[x]-));
  66. }
  67. }
  68. return ;
  69. }

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. ipython安装( jupyter)

    生产环境:win10 64位 pip的版本不是最新的,输入命令 python -m pip install --upgrade pip 更新我们的pip,pip不是最新的也会导致安装不了ipython ...

  2. Oracle 表空间的创建与管理

    Oracle数据库创建之后有一些默认的表空间随之被创建,查询数据字典 dba_data_files 可以得到数据库当前的所有表空间信息. select * from v$tablespace; sel ...

  3. [转帖]SAP一句话入门:Project System

    SAP一句话入门:Project System http://blog.vsharing.com/MilesForce/A621279.html 这是SAP ERP入门的最后一篇了. 我们这些死跑龙套 ...

  4. 剑指offer(15)

    题目: 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)). 书中的思路: 按照这个思路我们很容易写出以下代码: import java.util.S ...

  5. docker 操作镜像的基本操作

    以安装mysql为例 1.拉取镜像 docker pull mysql 错误的启动 [root@localhost ~]# docker run --name mysql01 -d mysql 42f ...

  6. python之路--MySQL数据库初识

    一 . MySQL安装 # 下载MySQL地址 https://dev.mysql.com/downloads # 要选稳定的,不要选最新的,稳定的就是半年以上没有出现过bug 现在5.6.43为绝大 ...

  7. 二、.Net 连接mycat

    一.mycat 单体的mysql已经过去 二.引用Mycat包 三.代码 using Pomelo.Data.MyCat; using System; using System.Collections ...

  8. Cherry.chen window.clipboardData实现剪切板操作总结 (好像只有ie好用)

    window.clipboardData的作用是在页面上将需要的东西复制到剪贴板上,提供了对于预定义的剪贴板格式的访问,以便在编辑操作中使用. 三个方法 (1)clearData(sDataForma ...

  9. CentOS 7 vi编辑命令

    用vi打开一个yum文件 vi /usr/bin/yum 按 i 键后  进入insert模式,进入insert模式后才能进行修改 修改完成后 按esc键进入command模式, 然后:wq 保存文件 ...

  10. 自定义 ASP.NET Identity Data Model with EF

    One of the first issues you will likely encounter when getting started with ASP.NET Identity centers ...