题面 首先可以写一个暴力dp的式子,非常经典的树形dp \(dp[i][0]\)表示\(i\)这个点没有驻军,\(dp[i][1]\)就是有驻军,\(j\)是\(i\)的孩子.那么显然: \[ \begin{align*} dp[i][0]&=dp[j][1]\\ dp[i][1]&=\min\{dp[j][0],dp[j][1]\} \end{align*} \] 然后我们发现,对于一个孩子\(j\),它的转移与其他孩子无关.也就是其他孩子的值对他没有影响. 这样的性质决定了这道题目的可…
我的倍增解法吊打动态 \(dp\) 全局平衡二叉树没学过 先讲 \(NOIP\) 范围内的倍增解法. 我们先考虑只有一个点取/不取怎么做. \(f[x][0/1]\) 表示取/不取 \(x\) 后,\(x\) 子树内的最小权覆盖集,\(g[x][0/1]\) 表示取/不取 \(x\) 后,除 \(x\) 子树的最小权覆盖集.那么这两个数组可以 \(O(n)\) 预处理出来. \[f[x][0]+=f[y][1]\] \[f[x][1]+=min(f[y][0],f[y][1])\] \[g[y]…
暴力dp非常显然,设f[i][0/1]表示i号点不选/选时i子树内的答案,则f[i][0]=Σf[son][1],f[i][1]=a[i]+Σmin(f[son][0],f[son][1]). 注意到B的部分分,可以想到每次修改只会对修改点到根的路径上的点的dp值产生影响. 考虑如何优化修改路径这一过程,先看只修改一个点的情况. 由于每次修改并非累积,事实上应该考虑一种预处理来快速得到答案,并且发现其实最终我们只需要f[root][].容易想到倍增.设f[x][k][0/1][0/1]表示x号点…
题意 求最小权值点覆盖. mmm次询问,每次给出两个点,分别要求每个点必须选或必须不选,输出每次的最小权值覆盖或者无解输出−1-1−1 题解 强制选或者不选可以看做修改权值为±∞\pm\infin±∞. 那么就是这道板题了. CODE #include <bits/stdc++.h> using namespace std; typedef long long LL; template<class T>inline void read(T &x) { char ch; in…
传送门 题意简述: mmm次询问,每次规定两个点必须选或者不选,求树上的带权最小覆盖. 思路: 考虑链分治+ddpddpddp 仍然是熟悉的套路,先考虑没有修改的状态和转移: 令fi,0/1f_{i,0/1}fi,0/1​表示强制iii不选/选时iii为根子树的带权最小覆盖. 显然有: fi,0=∑v∈sonfv,1f_{i,0}=\sum_{v\in son}f_{v,1}fi,0​=∑v∈son​fv,1​ fi,1=valp+∑v∈sonmin{fv,0,fv,1}f_{i,1}=val_…
\(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题"\) 顺便提一下他的[题解](因为按照这个思路写的,所以代码看起来也差不多) 因为比较复(胡)杂(炸),可能需要理解久一点 『题目』 参见 [洛谷 P5024] 『解析』 一.初步思考 如果不考虑多次询问的话,显然可以进行一次简单的树形DP,特殊判断一下当前的点(也就是城市)能不能选(放军队)就行了~ 但是显…
题目链接 这个$dark$题,嗯,不想说了. 法一:动态$dp$ 虽然早有听闻动态$dp$,但到最近才学,如果你了解动态$dp$,那就能很轻松做出这道题了.故利用这题在这里科普一下动态$dp$的具体内容. 我们先不考虑点上的强制选不选的限制,这是一个最小权边覆盖问题,大家肯定都会这道题的$O(nm)$的做法,这是一个很经典的树形$dp$.具体来讲就是一下两个转移: $$f_{x, 0} = \sum_{v} f_{v, 1} \qquad  f_{x, 1} = a_{x} + \sum_{v}…
NOIP2018提高组D2T3 ddp虽然好想,但是码量有点大(其实是我不会),因此本文用倍增优化树形DP来解决本题. 题意分析 给一棵树染色,每个节点染色需要一定的花费,要求相邻两个节点至少要有一个被染色,给出一些限制条件,求满足每个限制条件的最小花费为多少. 思路分析 首先判断无解的情况.显然,只有当$a,b$互为父子关系(这里的父子关系指的是严格相邻),且$x,y$都为0时才无解,其它情况都可以通过多染色来解. 很容易想到树形DP,那么具体状态如何设置呢?对于每个限制条件给出的两个点$a,…
题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖. 题解 ZZ码农题. 要用动态dp做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍正常的树形dp,求出g[i][0/1],0/1表示当前节点选或不选. 然后我们再倒腾出一个数组l[i][0/1]表示从当前点作为根,再扣掉当前子树的答案. 然后倍增处理dp[i][j][0/1][0/1]表示从i向上2i长度的链,起点和终点的选择情况,表示以下区域的答案. 比如这条黑色的链,它表示的…
可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a,x,sizeof(a)) using namespace std; typedef long long ll; typedef pair<int,int> pa; ; const ll inf=1e17; inline ll rd(){ ll x=;; ;c=getchar();} +c-',c…