首先我们需要注意一下的是,差分比较适用于修改比较多而查询比较少的情况。

一、序列上差分

借教室  这是一道二分答案,在check函数中用到差分技巧的一道题,譬如说我们要把一个序列中[l,r]区间都加上一个权值,我们可以把在 l 处加上这个值,在r+1处减去这个值,再对记录权值的数组求前缀和,那么我们就可以得到这个真正的权值数组。

题解 在链接里,代码就不放了=w=。

二、树上差分

树上差分可以分为在点权上的情况和 在边权上的情况

1:    点权 :

比如在树上把 从u到v的路径的某个权值都加上一个数,设这个权值数组val,那么我们需要在val[u],val[v]上加上这个值,并在val[lca(u,v)]上减去这个值,并在val[f[lca(u,v][0]]上减去这个值。

理论如斯

这个算法就经常用于统计树上路径某点/某边的经过次数。

例题1 [USACO15DEC]最大流Max Flow(不是网络流题目啦==)

给出若干路径,求被经过此处最多的点的经过次数。

Sol:树上倍增求LCA+树上差分记录+最后O(n)扫一遍更新。

总复杂度O(nlogn预处理+klogn求LCA+n更新)

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cmath>
  4. #include<queue>
  5. #define maxn 500900
  6.  
  7. using namespace std;
  8.  
  9. int n,k,t,ans,tot;
  10. int head[maxn],d[maxn],val[maxn],f[maxn][];
  11. struct node{
  12. int to,next;
  13. }edge[maxn*];
  14.  
  15. void add(int x,int y)
  16. {
  17. edge[++tot].next=head[x];
  18. head[x]=tot;
  19. edge[tot].to=y;
  20. }
  21.  
  22. void init_LCA()
  23. {
  24. queue<int>q;
  25. q.push();
  26. d[]=;
  27. while(!q.empty())
  28. {
  29. int u=q.front();
  30. q.pop();
  31. for(int i=head[u];i;i=edge[i].next)
  32. {
  33. int v=edge[i].to;
  34. if(d[v]) continue;
  35. d[v]=d[u]+;
  36. f[v][]=u;
  37. for(int j=;j<=t;j++)
  38. f[v][j]=f[f[v][j-]][j-];
  39. q.push(v);
  40. }
  41. }
  42. }
  43.  
  44. int LCA(int x,int y)
  45. {
  46. if(d[x]>d[y]) swap(x,y);
  47. for(int i=t;i>=;i--)
  48. if(d[f[y][i]]>=d[x]) y=f[y][i];
  49. if(x==y) return x;
  50. for(int i=t;i>=;i--)
  51. if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
  52. return f[x][];
  53. }
  54.  
  55. void review(int u,int fa)
  56. {
  57. for(int i=head[u];i;i=edge[i].next)
  58. {
  59. int v=edge[i].to;
  60. if(v==fa) continue;
  61. review(v,u);
  62. val[u]+=val[v];
  63. }
  64. ans=max(ans,val[u]);
  65. }
  66.  
  67. int main()
  68. {
  69. scanf("%d%d",&n,&k);
  70. t=log2(n)+;
  71. for(int i=;i<=n-;i++)
  72. {
  73. int x=,y=;
  74. scanf("%d%d",&x,&y);
  75. add(x,y),add(y,x);
  76. }
  77. init_LCA();
  78. while(k--)
  79. {
  80. int x=,y=;
  81. scanf("%d%d",&x,&y);
  82. int fa=LCA(x,y);
  83. // printf("%d\n",fa);
  84. val[x]++;val[y]++;
  85. val[fa]--;val[f[fa][]]--;
  86. }
  87. review(,);
  88. printf("%d",ans);
  89. return ;
  90. }

例题2  [JLOI2014]松鼠的新家

也是求点经过次数的=w=,稍有变动,需要在最后从第2个到达点到最后一个到达点的权值都减。(题意使然)

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cmath>
  4. #include<queue>
  5. #define maxn 300090
  6.  
  7. using namespace std;
  8.  
  9. int n,tot,t;
  10. int seq[maxn],head[maxn],val[maxn],d[maxn],f[maxn][];
  11. struct node{
  12. int to,next;
  13. }edge[maxn*];
  14.  
  15. void add(int x,int y)
  16. {
  17. edge[++tot].to=y;
  18. edge[tot].next=head[x];
  19. head[x]=tot;
  20. }
  21.  
  22. void LCA_prework()
  23. {
  24. queue<int>q;
  25. q.push(),d[]=;
  26. while(!q.empty())
  27. {
  28. int u=q.front();q.pop();
  29. for(int i=head[u];i;i=edge[i].next)
  30. {
  31. int v=edge[i].to;
  32. if(d[v]) continue;
  33. d[v]=d[u]+;
  34. f[v][]=u;
  35. for(int j=;j<=t;j++)
  36. f[v][j]=f[f[v][j-]][j-];
  37. q.push(v);
  38. }
  39. }
  40. }
  41.  
  42. int LCA(int x,int y)
  43. {
  44. if(d[x]>d[y]) swap(x,y);
  45. for(int i=t;i>=;i--)
  46. if(d[f[y][i]]>=d[x]) y=f[y][i];
  47. if(x==y) return x;
  48. for(int i=t;i>=;i--)
  49. if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
  50. return f[x][];
  51. }
  52.  
  53. void review(int u,int fa)
  54. {
  55. for(int i=head[u];i;i=edge[i].next)
  56. {
  57. int v=edge[i].to;
  58. if(v==fa) continue;
  59. review(v,u);
  60. val[u]+=val[v];
  61. }
  62. }
  63.  
  64. int main()
  65. {
  66. scanf("%d",&n);
  67. t=log2(n)+;
  68. for(int i=;i<=n;i++) scanf("%d",&seq[i]);
  69. for(int i=;i<=n-;i++)
  70. {
  71. int x=,y=;
  72. scanf("%d%d",&x,&y);
  73. add(x,y),add(y,x);
  74. }
  75. LCA_prework();
  76. for(int i=;i<=n-;i++)
  77. {
  78. int fa=LCA(seq[i],seq[i+]);
  79. val[seq[i]]++;val[seq[i+]]++;
  80. val[fa]--;val[f[fa][]]--;
  81. }
  82. review(,);
  83. for(int i=;i<=n;i++) val[seq[i]]--;
  84. for(int i=;i<=n;i++) printf("%d\n",val[i]);
  85. return ;
  86. }

(话说省选出板子题真的好么==)

2:    边权

给你一棵树,有n次修改操作,每次把u..v的路径权值加x,最后问从x..y的路径权值和。

例如有一次操作是把红点(u)到绿点(v)之间的路径全部加x。那么我就标记dlt[u]+=x,dlt[v]+=x。然后我们要在lca(u,v)处标记dlt[lca(u,v)]-=2x。这样就使得加x的效果只局限在u..v,不会向lca(u,v)的爸爸蔓延。

上面的话引用自@Sagittariusdalao。

例题:NOIp2015运输计划

val[x]就是x与它的父节点之间的“树边”被覆盖的次数

链接中有详细的题解==

小结:树上差分和树上倍增还是比较实用的,也比较灵活,需要加强举一反三能力==

序列/树上差分小结 By cellur925的更多相关文章

  1. poj3417 闇の連鎖 【树上差分】By cellur925

    闇の連鎖(yam.pas/c/cpp)题目描述传说中的暗之连锁被人们称为 Dark.Dark 是人类内心的黑暗的产物,古今中外的勇者们都试图打倒它.经过研究,你发现 Dark 呈现无向图的结构,图中有 ...

  2. [GXOI/GZOI2019]旧词(树上差分+树剖)

    前置芝士:[LNOI2014]LCA 要是这题放HNOI就好了 原题:\(\sum_{l≤i≤r}dep[LCA(i,z)]\) 这题:\(\sum_{i≤r}dep[LCA(i,z)]^k\) 对于 ...

  3. BZOJ2588 主席树 + 树上差分

    https://www.lydsy.com/JudgeOnline/problem.php?id=2588 题意:强制在线的询问树链权值第K小(无修) 这种类似于第K小的题,一般容易想到主席树,但是树 ...

  4. bzoj4326 树链剖分 + 线段树 // 二分 lca + 树上差分

    https://www.lydsy.com/JudgeOnline/problem.php?id=4326 题意:N个点的树上给M条树链,问去掉一条边的权值之后所有树链长度和的最大值最小是多少. 首先 ...

  5. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

  6. BZOJ3881 Coci2015Divljak(AC自动机+树上差分+树状数组)

    建出AC自动机及其fail树,每次给新加入的串在AC自动机上经过的点染色,问题即转化为子树颜色数.显然可以用dfs序转成序列问题树状数组套权值线段树解决,显然过不掉.事实上直接树上差分,按dfs序排序 ...

  7. [JLOI2014]松鼠的新家 树上差分

    差分 一开始竟然想分情况讨论来差分,然后发现各自情况要分析, 就是为了解决中间节点重复计算的问题, 结果 最后一想,中间重复计算了一次,那我最后减掉不就好了么,,, 那这就是一道差分裸题了(这是唯一不 ...

  8. 差分数组 and 树上差分

    差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易 ...

  9. Codeforces E. Alyona and a tree(二分树上差分)

    题目描述: Alyona and a tree time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

随机推荐

  1. Intel processor brand names-Xeon,Core,Pentium,Celeron----Quark

    http://en.wikipedia.org/wiki/Intel_Quark Intel Quark From Wikipedia, the free encyclopedia     Intel ...

  2. android Graphics类:概述及基本几何图形绘制

    当须要在Android上绘制图形时.就会用到Graphics类.Paint类.Paint就是相当于笔,而Canvas就是 纸.这里叫画布. 所以,凡有跟要要画的东西的设置相关的.比方大小,粗细,画笔颜 ...

  3. iOS之UI--使用SWRevealViewController 实现侧边菜单功能详解实例

     iOS之UI--使用SWRevealViewController 实现侧边菜单功能详解实例 使用SWRevealViewController实现侧边菜单功能详解 下面通过两种方法详解SWReveal ...

  4. fstab文件解析

    1 这个文件的用途 这个文件是启动时自动挂载指定的磁盘或者分区到系统目录下用的,提供给mount命令用. 2 文件解析 每一行是一次mount操作. 磁盘或者分区    挂载的目录     挂载的磁盘 ...

  5. Vijos 1921 严厉的班长 【状态压缩动态规划】

    严厉的班长 描述 木姑娘在班级里面是班长.虽然是副班长,却有着比正班长更高的威信,并深受小朋友们的爱戴. 每天眼保健操时间,木姑娘都要监督所有小朋友认真做眼保健操.整个过程被描述为n个时间段,第i个时 ...

  6. UIActivityIndicatorView控件的属性和方法

    对于UIActivityIndicatorView的使用,我们一般会创建一个背景View,设置一定的透明度,然后将UIActivityIndicatorView贴在背景View上,在我们需要的时候将这 ...

  7. Java 通过 HTTP 下载文件

    1. [代码]Download.java   package core.spider; import java.io.*;import java.net.*;import java.util.*; / ...

  8. 合并table中某一列相邻的相同的行

    合并table中某一列相邻的相同的行​1. [代码]合并table中某一列相邻的相同的行  <!DOCTYPE html><html>    <head>      ...

  9. html5--6-55 动画效果-关键帧动画

    html5--6-55 动画效果-关键帧动画 实例 @charset="UTF-8"; div{ width: 150px; height: 150px; font-size: 2 ...

  10. Java中的switch语句

    switch可以替代if..else..,另外据说switch采用二分搜索,效率会更高一点. switch(type) { case 1 : type_name="INCOMING" ...