问题:

有一些问题,通常见于二维的DP,另一维记录当前x的信息,但是这一维过大无法开下,O(nm)也无法通过。

但是如果发现,对于x,在第二维的一些区间内,取值都是相同的,并且这样的区间是有限个,就可以批量处理

思想:

通过动态开点线段树维护第二维,

如果某个节点没有儿子,那么这个节点区间都是同一个权值。

也即,一个节点是空节点,那么这个节点所有的值和父亲的值都一致。(其实它的兄弟也是空节点的)

对于序列的问题,

可以直接扫过去,修改某些位置的点。

或者线段树合并。

对于树上的问题,

线段树合并。

实现:

主要考虑什么时候线段树合并停止。以及pushdown的标记问题。

当x都没有儿子或者y都没有儿子时候,整个x的区间或整个y的区间都是同一个值,可以直接计算贡献转移过来(这个必须支持,否则不能整体DP)。

否则,pushdown,进行递归

pushdown时候建立新的儿子(如果之前没有)。

空间复杂度和时间复杂度基本一致。O(nlogn)

只要满足,在x都没有儿子或者y都没有儿子时候,可以快速合并然后return,那么就可以整体DP了。

例题1:[九省联考2018]秘密袭击coat

例题2:

【PKUSC 2019】D2T1 树染色

$dp[x][c]=\Pi (sumy-dp[y][c])$sumy表示y的所有dp[y][*]的和

在x都没有儿子或者y都没有儿子时候,我们要么知道每个x的值,要么知道每个y的值。

在x都没有儿子时候,把y的节点内每个数乘-1再加sumy,再乘上x区间的值。

y都没有儿子时候,直接用(sumy-val)乘给x即可。

code:

  1. #include<bits/stdc++.h>
  2. #define reg register int
  3. #define il inline
  4. #define fi first
  5. #define se second
  6. #define mk(a,b) make_pair(a,b)
  7. #define numb (ch^'0')
  8. #define pb push_back
  9. #define solid const auto &
  10. #define enter cout<<endl
  11. #define pii pair<int,int>
  12. using namespace std;
  13. typedef long long ll;
  14. template<class T>il void rd(T &x){
  15. char ch;x=;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
  16. for(x=numb;isdigit(ch=getchar());x=x*+numb);(fl==true)&&(x=-x);}
  17. template<class T>il void output(T x){if(x/)output(x/);putchar(x%+'');}
  18. template<class T>il void ot(T x){if(x<) putchar('-'),x=-x;output(x);putchar(' ');}
  19. template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
  20. namespace Modulo{
  21. const int mod=;
  22. int ad(int x,int y){return (x+y)>=mod?x+y-mod:x+y;}
  23. void inc(int &x,int y){x=ad(x,y);}
  24. int mul(int x,int y){return (ll)x*y%mod;}
  25. void inc2(int &x,int y){x=mul(x,y);}
  26. int qm(int x,int y=mod-){int ret=;while(y){if(y&) ret=mul(x,ret);x=mul(x,x);y>>=;}return ret;}
  27. }
  28. using namespace Modulo;
  29. namespace Miracle{
  30. const int N=2e5+;
  31. int n,m,k;
  32. struct node{
  33. int nxt,to;
  34. }e[*N];
  35. int hd[N],cnt;
  36. void add(int x,int y){
  37. e[++cnt].nxt=hd[x];
  38. e[cnt].to=y;
  39. hd[x]=cnt;
  40. }
  41. #define mid ((l+r)>>1)
  42. struct tr{
  43. int sum,mul,ad;
  44. int ls,rs,val;
  45. void op(){
  46. cout<<"SUM "<<sum<<" MUL "<<mul<<" AD "<<ad<<endl;
  47. }
  48. }t[+];
  49. int tot,S;
  50. vector<int>no[N];
  51. int rt[N];
  52. int nc(){
  53. ++tot;
  54. t[tot].sum=;t[tot].mul=;t[tot].ad=;
  55. t[tot].ls=t[tot].rs=;t[tot].val=;
  56. return tot;
  57. }
  58. void tag(int x,int l,int r,int ml,int aa){
  59. // cout<<" tag "<<x<<" l "<<l<<" r "<<r<<" ml "<<ml<<" ad "<<aa<<endl;
  60. // t[x].op();
  61. t[x].sum=mul(t[x].sum,ml);
  62. t[x].sum=ad(t[x].sum,mul(r-l+,aa));
  63. t[x].val=ad(mul(t[x].val,ml),aa);
  64. t[x].mul=mul(t[x].mul,ml);
  65. t[x].ad=ad(mul(t[x].ad,ml),aa);
  66. }
  67. void pushup(int x){
  68. t[x].sum=ad(t[t[x].ls].sum,t[t[x].rs].sum);
  69. }
  70. void pushdown(int x,int l,int r){
  71. if(!t[x].ls) t[x].ls=nc();
  72. if(!t[x].rs) t[x].rs=nc();
  73. tag(t[x].ls,l,mid,t[x].mul,t[x].ad);
  74. tag(t[x].rs,mid+,r,t[x].mul,t[x].ad);
  75. t[x].mul=;t[x].ad=;
  76. }
  77. void upda(int &x,int l,int r,int p){
  78. // cout<<" pp "<<p<<" x "<<x<<" l "<<l<<" r "<<r<<" sm "<<t[x].sum<<" mul "<<t[x].mul<<" ad "<<t[x].ad<<endl;
  79. // cout<<" ls "<<t[x].ls<<" rs "<<t[x].rs<<endl;
  80. if(!x) x=nc();
  81. if(l==r){
  82. // cout<<" ss "<<t[x].sum<<endl;
  83. t[x].sum=;
  84. t[x].val=;
  85. return;
  86. }
  87. pushdown(x,l,r);
  88. if(p<=mid) upda(t[x].ls,l,mid,p);
  89. else upda(t[x].rs,mid+,r,p);
  90. pushup(x);
  91. }
  92. int merge(int x,int y,int l,int r){
  93. if(!t[x].ls&&!t[x].rs){
  94. swap(x,y);
  95. int v=t[y].val;
  96. tag(x,l,r,mod-,S);
  97. tag(x,l,r,v,);
  98. }else if(!t[y].ls&&!t[y].rs){
  99. int v=t[y].val;
  100. tag(x,l,r,ad(S,mod-v),);
  101. }else{
  102. pushdown(x,l,r);pushdown(y,l,r);
  103. t[x].ls=merge(t[x].ls,t[y].ls,l,mid);
  104. t[x].rs=merge(t[x].rs,t[y].rs,mid+,r);
  105. pushup(x);
  106. }
  107. return x;//warining!!
  108. }
  109. void dfs(int x,int fa){
  110. rt[x]=nc();
  111. tag(rt[x],,m,,);
  112. for(reg i=hd[x];i;i=e[i].nxt){
  113. int y=e[i].to;
  114. if(y==fa) continue;
  115. dfs(y,x);
  116. S=t[rt[y]].sum;
  117. rt[x]=merge(rt[x],rt[y],,m);
  118. // cout<<y<<" back "<<x<<" : "<<" sum "<<t[rt[x]].sum<<endl;
  119. }
  120. for(solid c:no[x]){
  121. upda(rt[x],,m,c);
  122. }
  123. // cout<<x<<" : "<<" sum "<<t[rt[x]].sum<<endl;
  124. }
  125. int main(){
  126. rd(n);rd(m);rd(k);
  127. int x,y;
  128. for(reg i=;i<n;++i){
  129. rd(x);rd(y);
  130. add(x,y);add(y,x);
  131. }
  132. for(reg i=;i<=k;++i){
  133. rd(x);rd(y);
  134. no[x].push_back(y);
  135. }
  136. dfs(,);
  137. printf("%d",t[rt[]].sum);
  138. return ;
  139. }
  140.  
  141. }
  142. signed main(){
  143. Miracle::main();
  144. return ;
  145. }
  146.  
  147. /*
  148. Author: *Miracle*
  149. */

[学习笔记]整体DP的更多相关文章

  1. [学习笔记] 数位DP的dfs写法

    跟着洛谷日报走,算法习题全都有! 嗯,没错,这次我也是看了洛谷日报的第84期才学会这种算法的,也感谢Mathison大佬,素不相识,却写了一长篇文章来帮助我学习这个算法. 算法思路: 感觉dfs版的数 ...

  2. [学习笔记]区间dp

    区间 \(dp\) 1.[HAOI2008]玩具取名 \(f[l][r][W/I/N/G]\) 表示区间 \([l,r]\) 中能否压缩成 \(W/I/N/G\) \(Code\ Below:\) # ...

  3. [学习笔记]树形dp

    最近几天学了一下树形\(dp\) 其实早就学过了 来提高一下打开树形\(dp\)的姿势. 1.没有上司的晚会 我的人生第一道树形\(dp\),其实就是两种情况: \(dp[i][1]\)表示第i个人来 ...

  4. [学习笔记]插头dp

    基于连通性的状压dp 巧妙之处:插头已经可以表示内部所有状态了. 就是讨论麻烦一些. 简介 转移方法:逐格转移,分类讨论 记录状态方法:最小表示法(每次要重新编号,对于一类没用“回路路径”之类的题,可 ...

  5. 【学习笔记】dp基础

    知识储备:dp入门. 好了,完成了dp入门,我们可以做一些稍微不是那么裸的题了. dp基础,主要是做题,只有练习才能彻底掌握. 洛谷P1417 烹调方案 分析:由于时间的先后会对结果有影响,所以c[i ...

  6. 【学习笔记】dp入门

    知识点 动态规划(简称dp),可以说是各种程序设计中遇到的第一个坎吧,这篇博文是我对dp的一点点理解,希望可以帮助更多人dp入门.   先看看这段话 动态规划(dynamic programming) ...

  7. [学习笔记]动态dp

    其实就过了模板. 感觉就是带修改的dp [模板]动态dp 给定一棵n个点的树,点带点权. 有m次操作,每次操作给定x,y表示修改点x的权值为y. 你需要在每次操作之后求出这棵树的最大权独立集的权值大小 ...

  8. [BZOJ4011][HNOI2015] 落忆枫音(学习笔记) - 拓扑+DP

    其实就是贴一下防止自己忘了,毕竟看了题解才做出来 Orz PoPoQQQ 原文链接 Description 背景太长了 给定一个DAG,和一对点(x, y), 在DAG中由x到y连一条有向边,求生成树 ...

  9. webpack学习笔记--整体配置结构

    之前的章节分别讲述了每个配置项的具体含义,但没有描述它们所处的位置和数据结构,下面通过一份代码来描述清楚: const path = require('path'); module.exports = ...

随机推荐

  1. Spring2.5依靠注入的方式有三种

    Spring2.5依靠注入的方式有三种: 1.通过setter方法注入: 2.通过构造方法注入: 3.通过注解进行注入: 第一种方式:通过setter方法注入 Java代码 package com.t ...

  2. 洛谷P1313 [NOIP2011提高组Day2T1]计算系数

    P1313 计算系数 题目描述 给定一个多项式(by+ax)^k,请求出多项式展开后x^n*y^m 项的系数. 输入输出格式 输入格式: 输入文件名为factor.in. 共一行,包含5 个整数,分别 ...

  3. Leetcode15.3Sum三数之和

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

  4. web前端学习(二)html学习笔记部分(9)-- 响应式布局

    1.2.23  响应式布局基础 1.2.23.1  响应式布局介绍 1.响应式布局是2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多终端 -- 而不是为每个终端做一个特定的版本.这个概 ...

  5. jmeter 通过csv data set config 设置参数化后,执行结果显示为<EOF>

    通过csv data set config 设置参数化后,执行结果显示为<EOF>: 反复确认相应的参数的设置均没有问题,其中csv文件编码方式采用uft-8.在csv data set ...

  6. _STORAGE_WRITE_ERROR_:./Application/Runtime/Cache/Home/f8995a0e1afcdadc637612fae5a3b585.php

    将one think部署到服务器上出现下面的问题 _STORAGE_WRITE_ERROR_:./Application/Runtime/Cache/Home/f8995a0e1afcdadc6376 ...

  7. svn基本命令使用

    1.svn help:可以通过该命令查看svn的所有操作命令,包括命令的缩写 2.首先需要从svn库中checkout对应的项目: (1)svn项目路径为svn://192.168.1.1/mypro ...

  8. arcgis访问百度地图

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  9. UML时序图(Sequence Diagram)学习笔记

    什么是时序图时序图(Sequence Diagram),又名序列图.循序图,是一种UML交互图.它通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作. 让我们来看一看visio2016对时序 ...

  10. Docker.[2].安装Docker.

    Docker.[2].安装Docker. 学习Docker的时候,也是搜索了好多资料,捣鼓那些理论的东西.什么是镜像?什么是容器 ?特点?用途?.... 巴拉巴拉一大堆. 我这里不再讲述理论,只记录代 ...