重温NOIP2018的试题,发现只要好好想想还是能想出一些东西的。

比如说本题是一个DDP的模板题,硬是做成了倍增优化DP的题目。

对于给出的$n$个节点的树,每个点都有点权$v_i$,共$Q$次询问。

每次询问指定两个点的状态取或者不取,询问树中最小权覆盖集。

如果最小权覆盖集不存在,输出$-1$

对于$100\%$保证$1 \leq n,m \leq 10^5 , 1 \leq v_i \leq 10^9$

Solution :

  我们设$g[u][0/1]$表示节点$u$是否选择,$u$的子树最小权覆盖集。

  一个显然的转移是$g[u][0] = \sum\limits_{v \in u_{son}} g[v][1] , g[u][1] = val[u] + \sum\limits_{v \in u_{son}} min(g[v][0],g[v][1])$

  为了解决$Q$个询问,我们需要设倍增数组来优化上述转移。

​ 设$其中f[u][i][p][q] ( 其中p,q =0,1)$表示从$father(u)$到$u$向上跳$2^i$步的节点,其中$u$状态是$p $,$u$向上跳$2^i$得到的节点状态是$q$这段贡献最小值。

​ 我们显然可以通过一次$dfs$,计算出$f[u][0][0/1][0/1] , g[u][0/1]$的值

  • $f[u][0][0][0] = inf$
  • $f[u][0][0][1] = val[father(u)] + \sum\limits_{v \in father(u)_{son} v \neq u}min\{g[v][0],g[v][1]\}$
  • $f[u][0][1][0] =\sum\limits_{v \in father(u)_{son}} g[v][1]$
  • $f[u][0][1][1]= val[father(u)] + \sum\limits_{v \in father(u)_{son} v \neq u}min\{g[v][0],g[v][1]\}$

然后我们也能通过$O(n \ log_2 \ n)$的复杂度预处理上述的倍增的数组,和$lca$的数组

处理每个询问的时候,把$u,v$在同一条链上的情况和$u,v$不在一条链上的情况进行讨论

(主要是向上跳的位置及贡献计算不同)

在向上跳的时候记录两个变量$ret0,ret1$表示当前节点取或不取当前的子树最小权覆盖集。

由于向上跳的步数倍增预处理完毕,一次询问最多只会向上跳$log_2n$步,

所以本题的时间复杂度就是$O((n+m) log_2 n )$

  1. # include <bits/stdc++.h>
  2. # define int long long
  3. # define inf (1e12)
  4. using namespace std;
  5. const int N=5e5+;
  6. struct rec{ int pre,to;}a[N<<];
  7. int n,m,tot; char type[];
  8. int f[N][][][],g[N][],d[N][],dep[N];
  9. int sum1[N],sum2[N],head[N],val[N];
  10. inline int read()
  11. {
  12. int X=,w=; char c=;
  13. while(c<''||c>'') {w|=c=='-';c=getchar();}
  14. while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
  15. return w?-X:X;
  16. }
  17. void write(int x) {
  18. if (x<) putchar('-'),x=-x;
  19. if (x>) write(x/);
  20. putchar(''+x%);
  21. }
  22. void adde(int u,int v) {
  23. a[++tot].pre=head[u];
  24. a[tot].to=v;
  25. head[u]=tot;
  26. }
  27. void dfs1(int u,int fa) {
  28. dep[u]=dep[fa]+;
  29. g[u][]=; g[u][]=val[u]; d[u][]=fa;
  30. sum1[u]=; sum2[u]=;
  31. for (int i=head[u];i;i=a[i].pre) {
  32. int v=a[i].to; if (v==fa) continue;
  33. dfs1(v,u);
  34. g[u][]+=g[v][];
  35. g[u][]+=min(g[v][],g[v][]);
  36. sum1[u]+=g[v][];
  37. sum2[u]+=min(g[v][],g[v][]);
  38. }
  39. }
  40. void dfs2(int u,int fa) {
  41. for (int i=head[u];i;i=a[i].pre) {
  42. int v=a[i].to; if (v==fa) continue;
  43. dfs2(v,u);
  44. }
  45. if (u != ) {
  46. f[u][][][] = inf;
  47. f[u][][][] = val[fa] + sum2[fa] - min(g[u][],g[u][]);
  48. f[u][][][] = sum1[fa] - g[u][];
  49. f[u][][][] = val[fa] + sum2[fa] - min(g[u][],g[u][]);
  50. }
  51. }
  52. int lca(int u,int v) {
  53. if (dep[u]<dep[v]) swap(u,v);
  54. for (int i=;i>=;i--)
  55. if (dep[d[u][i]]>=dep[v]) u=d[u][i];
  56. if (u==v) return u;
  57. for (int i=;i>=;i--)
  58. if (d[u][i]!=d[v][i]) u=d[u][i],v=d[v][i];
  59. return d[u][];
  60. }
  61. int work2(int u,int op1,int v,int op2) {
  62. int ret0=g[u][],ret1=g[u][];
  63. if (op1 == ) ret0=inf; else ret1=inf;
  64. bool flag = true;
  65. int tmp0,tmp1;
  66. for (int i=;i>=;i--) {
  67. if (dep[d[u][i]]<=dep[v]) continue;
  68. tmp0=ret0,tmp1=ret1;
  69. ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  70. ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  71. u = d[u][i];
  72. }
  73.  
  74. tmp0=ret0,tmp1=ret1;
  75. ret0 = tmp1 + sum1[v] - g[u][];
  76. ret1 = min(tmp1,tmp0) + sum2[v] - min(g[u][],g[u][]) + val[v];
  77. if (op2 == ) ret1=inf; else ret0=inf;
  78. u = v;
  79. for (int i=;i>=;i--) {
  80. if (dep[d[u][i]]<dep[]) continue;
  81. tmp0=ret0,tmp1=ret1;
  82. ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  83. ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  84. u=d[u][i];
  85. }
  86. int ans = min(ret0,ret1);
  87. if (ans>=inf) return -; else return ans;
  88. }
  89. int work(int u,int op1,int v,int op2) {
  90. if (dep[u]<dep[v]) swap(u,v),swap(op1,op2);
  91. int l=lca(u,v);
  92. if (l == v) return work2(u,op1,v,op2);
  93. int ret0=g[u][],ret1=g[u][];
  94. if (op1 == ) ret0=inf; else ret1=inf;
  95. bool flag = true; int tmp0,tmp1;
  96. for (int i=;i>=;i--) {
  97. if (dep[d[u][i]]<=dep[l]) continue;
  98. tmp0=ret0,tmp1=ret1;
  99. ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  100. ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  101. u = d[u][i];
  102. }
  103. int val1[]; val1[] = ret0; val1[] = ret1;
  104. ret0=g[v][],ret1=g[v][];
  105. if (op2 == ) ret0=inf; else ret1=inf;
  106. flag = true;
  107. for (int i=;i>=;i--) {
  108. if (dep[d[v][i]]<=dep[l]) continue;
  109. tmp0=ret0,tmp1=ret1;
  110. ret0 = min(tmp0+f[v][i][][],tmp1+f[v][i][][]);
  111. ret1 = min(tmp0+f[v][i][][],tmp1+f[v][i][][]);
  112. v = d[v][i];
  113. }
  114. int val2[]; val2[] = ret0; val2[] = ret1;
  115. ret0 = val1[]+val2[]+sum1[l]-g[u][]-g[v][];
  116. ret1 = val[l] + min(val1[],val1[]) + min(val2[],val2[]) + sum2[l] - min(g[u][],g[u][]) - min(g[v][],g[v][]);
  117. u = l;
  118. for (int i=;i>=;i--) {
  119. if (dep[d[u][i]]<dep[]) continue;
  120. tmp0=ret0,tmp1=ret1;
  121. ret0 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  122. ret1 = min(tmp0+f[u][i][][],tmp1+f[u][i][][]);
  123. u=d[u][i];
  124. }
  125.  
  126. int ans = min(ret0,ret1);
  127. if (ans>=inf) return -; else return ans;
  128. }
  129. signed main()
  130. {
  131. n=read();m=read(); scanf("%s",type);
  132. for (int i=;i<=n;i++) val[i]=read();
  133. for (int i=;i<=n;i++) {
  134. int u=read(),v=read();
  135. adde(u,v); adde(v,u);
  136. }
  137. dfs1(,); dfs2(,);
  138. for (int i=;i<=;i++)
  139. for (int j=;j<=n;j++)
  140. d[j][i]=d[d[j][i-]][i-];
  141. for (int i=;i<=;i++)
  142. for (int u=;u<=n;u++) {
  143. f[u][i][][]=f[u][i][][]=f[u][i][][]=f[u][i][][]=inf;
  144. for (int p=;p<=;p++) {
  145. f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
  146. f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
  147. f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
  148. f[u][i][][] = min(f[u][i][][],f[u][i-][][p] + f[d[u][i-]][i-][p][]);
  149. }
  150. }
  151. while (m--) {
  152. int u=read(),op1=read(),v=read(),op2=read();
  153. int ans = work(u,op1,v,op2);
  154. write(ans); putchar('\n');
  155. }
  156. return ;
  157. }

defense

『NOIP 2019Day2 T3』 保卫王国(defense)的更多相关文章

  1. 『保卫王国 树上倍增dp』

    保卫王国 Description Z 国有n座城市,n - 1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需 ...

  2. 竞赛题解 - NOIP2018 保卫王国

    \(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...

  3. js实现『加载更多』功能实例

    DEMO : 滚动加载示例 关于如何实现『加载更多』功能,网上有插件可用,例如比较著名的使用iscroll.js实现的上拉加载更多.下拉刷新功能. 但实际用起来却是很麻烦.由于是第三方插件,要按照对方 ...

  4. 『Asp.Net 组件』Asp.Net 服务器组件 内嵌JS:让自己的控件动起来

    代码: using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace ...

  5. 2018-2019-2 20165221『网络对抗技术』Exp4:恶意代码分析

    2018-2019-2 20165221『网络对抗技术』Exp4:恶意代码分析 实验要求: 是监控你自己系统的运行状态,看有没有可疑的程序在运行. 是分析一个恶意软件,就分析Exp2或Exp3中生成后 ...

  6. 『Asp.Net 组件』Asp.Net 服务器组件 内嵌图片:自己的图片控件

    代码: using System; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace ...

  7. 『Asp.Net 组件』第一个 Asp.Net 服务器组件:自己的文本框控件

    代码: using System.Web; using System.Web.UI; using System.Web.UI.WebControls; namespace DemoWebControl ...

  8. 『Asp.Net 组件』Asp.Net 服务器组件 的开发优势和劣势

    在写<Asp.Net 服务器组件系列文档>之前,笔者不才,揣测微软战略用意: 微软利益诉求莫过于 微软产品和技术的市场份额: 因此,微软战略之一莫过于将 所有开发人员 团聚在 微软周围,以 ...

  9. 2017-2018-2 20155303『网络对抗技术』Exp6:信息收集与漏洞扫描

    2017-2018-2 20155303『网络对抗技术』 Exp6:信息收集与漏洞扫描 --------CONTENTS-------- 一.原理与实践说明 1.实践内容 2.基础问题 二.实践过程记 ...

随机推荐

  1. win10 Snipaste 截图软件

    安装教程:搜索 snipaste,网上可以直接下载 使用教程: 1)截图按钮:F1 2)粘贴按钮:F3

  2. react中数据持久化缓存redux-persist

    一.安装redux-persist: npm install redux-persist --save 二..babelrc中增加redux-persist配置: "plugins" ...

  3. 2-Perl 环境安装

    1.Perl 环境安装在我们开始学习 Perl 语言前,我们需要先安装 Perl 的执行环境.Perl 可以在以下平台下运行:Unix (Solaris, Linux, FreeBSD, AIX, H ...

  4. C#实现鼠标滚筒缩放界面的效果

    elementCanvas继承UserControl 声明属性: #region 缩放属性添加 float ratio = 1.0f; public float Ratio { set { ratio ...

  5. 解决EntityFramework与System.ComponentModel.DataAnnotations命名冲突

    比如,定义entity时指定一个外键, [ForeignKey("CustomerID")] public Customer Customer { get; set; } 编译时报 ...

  6. O049、准备 LVM Volume Provider

    参考https://www.cnblogs.com/CloudMan6/p/5597790.html   Cinder 真正负责volume 管理的组件是 volume provider .Cinde ...

  7. LintCode 547---两数组的交集

    public class Solution { /** * 给出两个数组,写出一个方法求出它们的交集 * @param nums1: an integer array * @param nums2: ...

  8. ext grid添加2行topbar

    bbar: paginToolbar(this.getStore()), dockedItems: [{ xtype: 'toolbar', dock: 'top', items: me.create ...

  9. js之数据类型(对象类型——构造器对象——数组2)

    一.数组空位与undefined 数组空位:数组的某一个位置没有任何值 产生空位的原因:数组中两个逗号之间不放任何值:用new Array()的方法,参数里是个数字:通过一个不存在的下标去增加数组:增 ...

  10. JS遍历对象和数组总结

    在日常工作过程中,我们对于javaScript遍历对象.数组的操作是十分的频繁的,今天把经常用到的方法总结一下! 一.遍历对象 1.使用Object.keys()遍历 返回一个数组,包括对象自身的(不 ...