Uoj 441 保卫王国

  • 动态 \(dp\) .今天才来写这个题.
  • 设 \(f[u][0/1]\) 表示子树 \(u\) 中不选/选 \(u\) 时的最小权值和,显然有:\(f[u][0]=\sum f[v][1] ,f[u][1]=w[u]+\sum \min(f[v][0],f[v][1])​\) .
  • 现在要资瓷修改 \(x\) 的点权 \(w[x]\) ,容易发现修改后只会影响 \(x\) 到根节点这一条链上的 \(f\) 值.若暴力更新这一条链,在树深度大时,时间复杂度仍是 \(O(nm)\) 的.考虑使用树剖来维护,尝试快速更新信息.
  • 由于树剖后,一个节点到根节点的路径上,轻边/重链都不会超过 \(logn\) 条,可以暴力修改轻儿子的贡献,用数据结构来维护重链.那么轻重儿子的信息需要分开存,用 \(g[u][0/1]\) 表示子树 \(u\) 除去重儿子的子树后, 不选/选 \(u\) 时的最小权值和.
  • 转移可以用下面这个转移矩阵表示,这里是 Min-plus matrix multiplication ,即将原来矩阵乘法的乘法换成加法,加法换成取 \(\min​\) .仍然满足结合律..(这东西还有其他用法,可以点进去看看)

  • 用线段树维护区间矩阵乘积即可.

参考

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. inline ll read()
  5. {
  6. ll out=0,fh=1;
  7. char jp=getchar();
  8. while ((jp>'9'||jp<'0')&&jp!='-')
  9. jp=getchar();
  10. if (jp=='-')
  11. fh=-1,jp=getchar();
  12. while (jp>='0'&&jp<='9')
  13. out=out*10+jp-'0',jp=getchar();
  14. return out*fh;
  15. }
  16. const int MAXN=1e5+10;
  17. int n,m;
  18. int nx[MAXN<<1],to[MAXN<<1],head[MAXN],cnt=0;
  19. inline void addedge(int u,int v)
  20. {
  21. ++cnt;
  22. nx[cnt]=head[u];
  23. to[cnt]=v;
  24. head[u]=cnt;
  25. swap(u,v);
  26. ++cnt;
  27. nx[cnt]=head[u];
  28. to[cnt]=v;
  29. head[u]=cnt;
  30. }
  31. ll w[MAXN];
  32. ll f[MAXN][2],g[MAXN][2];
  33. int fa[MAXN],mxson[MAXN],siz[MAXN],dep[MAXN],dfn[MAXN],rnk[MAXN],top[MAXN],bot[MAXN],idx=0;
  34. void DP(int u,int Fa)
  35. {
  36. f[u][1]=w[u];
  37. for(int i=head[u];i;i=nx[i])
  38. {
  39. int v=to[i];
  40. if(v==Fa)
  41. continue;
  42. DP(v,u);
  43. f[u][0]+=f[v][1];
  44. f[u][1]+=min(f[v][0],f[v][1]);
  45. }
  46. }
  47. void dfs1(int u,int Fa)
  48. {
  49. fa[u]=Fa;
  50. siz[u]=1;
  51. dep[u]=dep[Fa]+1;
  52. for(int i=head[u];i;i=nx[i])
  53. {
  54. int v=to[i];
  55. if(v==Fa)
  56. continue;
  57. dfs1(v,u);
  58. siz[u]+=siz[v];
  59. if(siz[v]>siz[mxson[u]])
  60. mxson[u]=v;
  61. }
  62. }
  63. void dfs2(int u,int tp)
  64. {
  65. top[u]=tp;
  66. dfn[u]=++idx;
  67. rnk[idx]=u;
  68. if(mxson[u])
  69. dfs2(mxson[u],tp);
  70. for(int i=head[u];i;i=nx[i])
  71. {
  72. int v=to[i];
  73. if(v!=fa[u] && v!=mxson[u])
  74. dfs2(v,v);
  75. }
  76. }
  77. const ll inf=1e18;
  78. struct node{
  79. ll v[2][2];
  80. int l,r;
  81. node(){v[0][0]=v[0][1]=v[1][0]=v[1][1]=inf;}
  82. node operator * (const node &rhs) const
  83. {
  84. node res;
  85. res.l=l,res.r=rhs.r;
  86. for(int k=0;k<2;++k)
  87. for(int i=0;i<2;++i)
  88. for(int j=0;j<2;++j)
  89. res.v[i][j]=min(res.v[i][j],v[i][k]+rhs.v[k][j]);
  90. return res;
  91. }
  92. };
  93. node val[MAXN];
  94. struct SegTree{
  95. node Tree[MAXN<<2];
  96. #define root Tree[o]
  97. #define lson Tree[o<<1]
  98. #define rson Tree[o<<1|1]
  99. inline void pushup(int o)
  100. {
  101. root=lson*rson;
  102. }
  103. void BuildTree(int o,int l,int r)
  104. {
  105. root.l=l,root.r=r;
  106. if(l==r)
  107. {
  108. int u=rnk[l],g[2];
  109. g[0]=0,g[1]=w[u];
  110. for(int i=head[u];i;i=nx[i])
  111. {
  112. int v=to[i];
  113. if(v==fa[u] || v==mxson[u])
  114. continue;
  115. g[0]+=f[v][1];
  116. g[1]+=min(f[v][0],f[v][1]);
  117. }
  118. root.v[0][0]=inf,root.v[0][1]=g[0];
  119. root.v[1][0]=root.v[1][1]=g[1];
  120. val[l]=root;
  121. return;
  122. }
  123. int mid=(l+r)>>1;
  124. BuildTree(o<<1,l,mid);
  125. BuildTree(o<<1|1,mid+1,r);
  126. pushup(o);
  127. }
  128. void update(int o,int pos)
  129. {
  130. int l=root.l,r=root.r;
  131. if(l==r)
  132. {
  133. root=val[pos];
  134. return;
  135. }
  136. int mid=(l+r)>>1;
  137. if(pos<=mid)
  138. update(o<<1,pos);
  139. else
  140. update(o<<1|1,pos);
  141. pushup(o);
  142. }
  143. node query(int o,int L,int R)
  144. {
  145. int l=root.l,r=root.r;
  146. if(L<=l && r<=R)
  147. return root;
  148. int mid=(l+r)>>1;
  149. if(R<=mid)
  150. return query(o<<1,L,R);
  151. if(L>mid)
  152. return query(o<<1|1,L,R);
  153. return query(o<<1,L,R)*query(o<<1|1,L,R);
  154. }
  155. }T;
  156. node query(int x)
  157. {
  158. return T.query(1,dfn[x],dfn[bot[x]]);
  159. }
  160. ll getans()
  161. {
  162. node s=query(1);
  163. return min(s.v[0][1],s.v[1][1]);
  164. }
  165. void upd(int x,ll nv)
  166. {
  167. val[dfn[x]].v[1][0]-=w[x]-nv;
  168. val[dfn[x]].v[1][1]-=w[x]-nv;
  169. w[x]=nv;
  170. while(x)
  171. {
  172. node org=query(top[x]);
  173. T.update(1,dfn[x]);
  174. node nx=query(top[x]);
  175. x=fa[top[x]];
  176. val[dfn[x]].v[0][1]+=nx.v[1][1]-org.v[1][1];
  177. val[dfn[x]].v[1][0]+=min(nx.v[1][1],nx.v[0][1])-min(org.v[1][1],org.v[0][1]);
  178. val[dfn[x]].v[1][1]=val[dfn[x]].v[1][0];
  179. }
  180. }
  181. void solve(int x1,int t1,int x2,int t2)
  182. {
  183. if(t1==0 && t2==0 && (fa[x1]==x2 || fa[x2]==x1))
  184. return void(puts("-1"));
  185. ll v1=w[x1],v2=w[x2];
  186. upd(x1,v1+(t1?-inf:inf));
  187. upd(x2,v2+(t2?-inf:inf));
  188. ll res=getans();
  189. res+=t1?inf:0;
  190. res+=t2?inf:0;
  191. printf("%lld\n",res);
  192. upd(x1,v1);
  193. upd(x2,v2);
  194. }
  195. char tip[5];
  196. signed main()
  197. {
  198. //freopen("tx.in","r",stdin);
  199. n=read(),m=read();
  200. scanf("%s",tip);
  201. for(int i=1;i<=n;++i)
  202. w[i]=read();
  203. for(int i=1;i<n;++i)
  204. {
  205. int u=read(),v=read();
  206. addedge(u,v);
  207. }
  208. DP(1,0);
  209. dfs1(1,0);
  210. dfs2(1,1);
  211. for(int i=1;i<=n;++i)
  212. {
  213. if(i==top[i])
  214. {
  215. int t=i;
  216. while(mxson[t])
  217. t=mxson[t];
  218. bot[i]=t;
  219. }
  220. }
  221. T.BuildTree(1,1,n);
  222. while(m--)
  223. {
  224. int a=read(),b=read(),c=read(),d=read();
  225. solve(a,b,c,d);
  226. }
  227. return 0;
  228. }

Uoj 441 保卫王国的更多相关文章

  1. noip2018 d2t3 保卫王国 解题报告

    保卫王国 电脑卡懒得把题面挪过来了. 朴素 \[ dp_{i,0}=\sum dp_{s,1}\\ dp_{i,1}=\sum \min(dp_{s,0},dp_{s,1})+p_i \] 然后直接动 ...

  2. LG5024 保卫王国

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

  3. 「NOIP2018」保卫王国

    「NOIP2018保卫王国」 题目描述 有一棵 \(n\) 个点, 点有点权 \(a_i\),\(m\) 组询问, 每次求钦点两个节点必须选或者必须不选后的树上最小点覆盖. \(1 \leq n, m ...

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

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

  5. [NOIP2018TG]保卫王国

    [NOIP2018TG]保卫王国 BZOJ luogu 当动态dp模板题写的,(全集-最大点权独立集)不能放军队的+inf,必须放军队-inf即可 注意矩阵乘法的顺序问题 #define ll lon ...

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

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

  7. 【比赛】NOIP2018 保卫王国

    DDP模板题 #include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double ...

  8. luogu5024 [NOIp2018]保卫王国 (动态dp)

    可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...

  9. NOIP2018保卫王国

    题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖. 题解 ZZ码农题. 要用动态dp做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍 ...

随机推荐

  1. TCGA学习1--下载level3 level4数据

    1.使用firehose_get   下载level3 level4数据 https://confluence.broadinstitute.org/display/GDAC/Download exa ...

  2. Go连接MySql数据库Error 1040: Too many connections错误解决

    原文:https://my.oschina.net/waknow/blog/205654 摘要: 使用Go链接数据库时,由于连接释放不当会在一段时间以后产生too many connections的错 ...

  3. IOS-程序员和设计师必备的20个CSS工具

    程序员和设计师必备的20个CSS工具   CSS工具是现今网站开发人员和设计人员使用的最必要和最重要的工具之一.这是因为这些CSS工具,可以为开发人员和设计人员简化手头的工作,大大减少web开发和设计 ...

  4. pip 使用总结

    pip的安装: Windows Python2.7 以上的版本均自带pip,安装的时候记得勾选对应的选项即可. 安装easy_install, 通过easy_install pip 下载[easy_s ...

  5. linux下面安装maven

    maven作为最近比较火的项目管理工具,对项目的jar包及其开元添加相应的插件的管理,很方便. 安装maven: 在官网上面去下载最新的maven的压缩包,apache-maven-3.3.1-bin ...

  6. 034——VUE中表单控件处理之使用vue控制radio表单的实例操作

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. java程序设计基础篇 复习笔记 第二单元

    1原始数据类型(primitive data type) == 基本类型 (fundamental type)byte short int long float double char boolean ...

  8. 数据存储-- Core Data的使用(一)

    一.概念 1.Core Data 是数据持久化存储的最佳方式 2.数据最终的存储类型可以是:SQLite数据库,XML,二进制,内存里,或自定义数据类型 在Mac OS X 10.5Leopard及以 ...

  9. TableviewCell嵌套TextView自动换行

    TableviewCell嵌套TextView自动换行 欢迎到github上去下载源码Demo, github链接:https://github.com/mengzhihun6 效果图:

  10. C++11_shared_ptr

    版权声明:本文为博主原创文章,未经博主允许不得转载. shared_ptr智能指针的一种,它的使用类似于auto_ptr. shared_ptr它有两个指针,一个指向引用计数,一个指向data.由于拥 ...