JZOJ5966. [NOIP2018TGD2T3] 保卫王国 (动态DP做法)
题目大意
这还不是人尽皆知?
有一棵树, 每个节点放军队的代价是\(a_i\), 一条边连接的两个点至少有一个要放军队, 还有\(q\)次询问, 每次规定其中的两个一定需要/不可放置军队, 问这样修改以后的最小代价.
解题思路
考虑一个朴素的DP, 设\(f_{x,0/1}\)表示这个点选/不选的最小代价. 显然有
\]
\]
其中\(y\)是\(x\)的儿子. 最后的答案显然是\(min(f_{1,0}, f_{1,1})\)(1是根)
注意到我们每一次修改以后, 影响到的是从这个点到根节点的一条链. 我们需要快速修改这一段的\(f\)值. 怎么样可以使这个操作的时间复杂度变得正确一点呢? 显然树剖吧.
那就剖咯. 对轻重儿子区别对待. 设\(g_{x,0/1}\)表示\(x\)这个点选/不选, 除了重儿子外的最小代价. 显然有
\]
\]
只不过是少了一个重儿子而已
那么\(f\)可以借助\(g\)转移过来.
\]
\]
问题来了. 怎么维护一条链的信息?
考虑重新定义矩阵乘法, 若\(AB=C\), 则
\]
于是转移方程可以写成如下
+\infty & g_{x,0}\\
g_{x,1} & g_{x,1}
\end{bmatrix}
\begin{bmatrix}
f_{son,0}\\
f_{son,1}
\end{bmatrix}
=
\begin{bmatrix}
f_{x,0} \\
f_{x,1}
\end{bmatrix}
\]
在每一条链上维护\(g\)所在矩阵的乘积. 把一个询问按照重链分解成几条从当前点到根节点的链即可. 考虑当我们限制一个点强制选/不选后, 只需要把\(g\)数组对应的值赋成\(+\infty\)即可.
后记
其实一次有两个被限制了, 就是在暗示我们除了动态DP还有更简单的联赛做法.
但是我太懒了, 而且没做过树链剖分的题, 所以试一下(没错蒟蒻的第一个树链剖分就是做动态DP)
(可能是本人写过最长的Code?)
#include <cstdio>
#include <cstring>
#define N 100010
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3fll
#define init(a, b) memset(a, b, sizeof(a))
#define fo(i, a, b) for(int i = (a); i <= (b); ++i)
#define fd(i, a, b) for(int i = (a); i >= (b); --i)
//#pragma GCC optimize(2)
using namespace std;
inline int read() // notice : 1. long long ? 2. negative ?
{
int x = 0; char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return x;
}
inline ll min(ll a, ll b){return a < b ? a : b;}
struct Matrix
{
ll a[2][2];
inline Matrix(){init(a, 0x3f);}
inline Matrix(int){a[0][0] = a[1][1] = 0; a[0][1] = a[1][0] = INF;}
inline Matrix(ll g0, ll g1){a[0][0] = INF, a[0][1] = g0, a[1][0] = a[1][1] = g1;}
inline Matrix operator*(const Matrix &b)
{
Matrix ret;
fo(i, 0, 1) fo(j, 0, 1) fo(k, 0, 1) ret.a[i][j] = min(ret.a[i][j], a[i][k] + b.a[k][j]);
return ret;
}
}tr[N << 2];
int n, q, ls[N << 2], rs[N << 2], rt[N], top[N], fa[N], sz[N], son[N], dfn[N], end[N], a[N], to[N << 1], pre[N << 1], last[N];
ll f[N][2], g[N][2];
#define mid ((l + r) >> 1)
void build(int &t, int l, int r)
{
static int tot = 0;
!t && (t = ++tot);
if(l == r) return ;
build(ls[t], l, mid); build(rs[t], mid + 1, r);
}
void insert(int t, int l, int r, Matrix v, int w)
{
if(l == r) return (void)(tr[t] = v, 0);
w <= mid ? insert(ls[t], l, mid, v, w) : insert(rs[t], mid + 1, r, v, w);
tr[t] = tr[ls[t]] * tr[rs[t]];
}
Matrix query(int t, int l, int r, int fl, int fr)
{
if(fl <= l && r <= fr) return tr[t];
Matrix ret(1);
fl <= mid && (ret = ret * query(ls[t], l, mid, fl, fr), 1);
fr > mid && (ret = ret * query(rs[t], mid + 1, r, fl, fr), 1);
return ret;
}
inline void add(int u, int v){static int tot = 0; to[++tot] = v, pre[tot] = last[u], last[u] = tot;}
inline void dfs1(int u)
{
sz[u] = 1, f[u][1] = a[u];
for(int i = last[u]; i; i = pre[i])
if(to[i] ^ fa[u])
{
int v = to[i];
fa[v] = u; dfs1(v), sz[u] += sz[v];
f[u][0] += f[v][1], f[u][1] += min(f[v][0], f[v][1]);
sz[v] > sz[son[u]] && (son[u] = v);
}
}
inline void dfs2(int u)
{
static int tot = 0;
dfn[u] = ++tot, g[u][1] = a[u];
if(son[u]) top[son[u]] = top[u], dfs2(son[u]), end[u] = end[son[u]];
else end[u] = u;
for(int i = last[u]; i; i = pre[i])
if(to[i] ^ fa[u] && to[i] ^ son[u])
{
int v = to[i];
top[v] = v;
g[u][0] += f[v][1], g[u][1] += min(f[v][0], f[v][1]);
dfs2(v);
}
}
inline void update(int x)
{
for(; x; x = fa[x])
{
insert(rt[top[x]], dfn[top[x]], dfn[end[x]], Matrix(g[x][0], g[x][1]), dfn[x]);
Matrix p = tr[rt[x = top[x]]];
// printf("f[%d] : %lld %lld\n", x, f[x][0], f[x][1]);
g[fa[x]][0] -= f[x][1], g[fa[x]][1] -= min(f[x][0], f[x][1]);
f[x][0] = min(p.a[0][0], p.a[0][1]), f[x][1] = min(p.a[1][0], p.a[1][1]);
g[fa[x]][0] += f[x][1], g[fa[x]][1] += min(f[x][0], f[x][1]);
}
}
int main()
{
freopen("defense.in", "r", stdin);
freopen("defense.out", "w", stdout);
n = read(), q = read(); scanf(" %*s");
fo(i, 1, n) a[i] = read();
int u, v, x, y; ll t1, t2;
fo(i, 2, n) u = read(), v = read(), add(u, v), add(v, u);
top[1] = 1;
dfs1(1);
dfs2(1);
fo(i, 1, n) if(top[i] == i) build(rt[i], dfn[i], dfn[end[i]]);
fo(i, 1, n) insert(rt[top[i]], dfn[top[i]], dfn[end[i]], Matrix(g[i][0], g[i][1]), dfn[i]);
fo(i, 1, q)
{
u = read(), x = read() ^ 1, v = read(), y = read() ^ 1;
t1 = g[u][x], t2 = g[v][y];
g[u][x] = INF, update(u), g[v][y] = INF, update(v);
ll ans = min(f[1][0], f[1][1]);
printf("%lld\n", ans < INF ? ans : -1);
g[u][x] = t1, update(u), g[v][y] = t2, update(v);
}
return 0;
}
JZOJ5966. [NOIP2018TGD2T3] 保卫王国 (动态DP做法)的更多相关文章
- luogu5024 [NOIp2018]保卫王国 (动态dp)
可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...
- 【NOIP2018】保卫王国 动态dp
此题场上打了一个正确的$44pts$,接着看错题疯狂$rush$“正确”的$44pts$,后来没$rush$完没将之前的代码$copy$回去,直接变零分了..... 这一题我们显然有一种$O(nm)$ ...
- luoguP5024 保卫王国 动态dp
题目大意: emmmmm 题解: QAQ #include <cstdio> #include <cstring> #include <iostream> usin ...
- P5024 保卫王国(动态dp/整体dp/倍增dp)
做法(倍增) 最好写的一种 以下0为不选,1为选 \(f_{i,0/1}\)为\(i\)子树的最小值,\(g_{i,0/1}\)为除i子树外的最小值 \(fh_{i,j,0/1,0/1}\)为确定\( ...
- LuoguP5024 保卫王国(动态DP,LCT)
最小权覆盖集 = 全集 - 最大权独立集 强制取点.不取点可以使用把权值改成正无穷或负无穷实现 接下来就是经典的"动态最大权独立集"了 O(nlogn). 这不是我说的,是immo ...
- BZOJ 5466: [Noip2018]保卫王国 动态DP
Code: // luogu-judger-enable-o2 #include<bits/stdc++.h> #define ll long long #define lson (now ...
- P5024 保卫王国[倍增+dp]
窝当然不会ddp啦,要写这题当然是考虑优化裸dp啦,但是这题非常麻烦,于是变成了黑题. 首先,这个是没有上司的舞会模型,求图的带权最大独立集. 不考虑国王的限制条件,有 \[ dp[x][0]+=dp ...
- Uoj 441 保卫王国
Uoj 441 保卫王国 动态 \(dp\) .今天才来写这个题. 设 \(f[u][0/1]\) 表示子树 \(u\) 中不选/选 \(u\) 时的最小权值和,显然有:\(f[u][0]=\sum ...
- 动态 DP 学习笔记
不得不承认,去年提高组 D2T3 对动态 DP 起到了良好的普及效果. 动态 DP 主要用于解决一类问题.这类问题一般原本都是较为简单的树上 DP 问题,但是被套上了丧心病狂的修改点权的操作.举个例子 ...
随机推荐
- zabbix之源码安装
#:官网地址 https://www.zabbix.com/documentation/4.0/zh/manual/installation/install #:解压并创建用户 root@ubuntu ...
- LoadRunner中怎么设置密码参数化与用户名关联
对密码参数化时从parameter里的"Select next row"列表中选择Same Line As这一选项,意思就是每一个密码参数化取值与对应行的用户名关联起来了
- 小程序中使用less(最优方式)
写惯了less/sass,但是现在开发小程序缺还是css,很不习惯. 在网上搜的教程,要么是gulp,要么就是vscode的Easy-less的插件. 传统方式 我们来对比,这两种方式的优劣. Gul ...
- OpenStack之二: 安装OpenStack的yum源及相关组件
#: 在所有节点执行 [root@localhost ~]# yum install centos-release-openstack-stein -y #: 安装相关组件(只在管理端和计算几点安装) ...
- 【Linux】【Problems】在fedora 9上解决依赖问题
summary: 在32bit的fedora9上安装EMC客户端遇到无法解决的依赖问题 detail: rpm 安装: [root@hcszmons02 tmp]# rpm -ivh lgtoclnt ...
- Spring 文档汇总
Spring Batch - Reference Documentation Spring Batch 参考文档中文版 Spring Batch 中文文档 Table 2. JdbcCursorIte ...
- 连接opcserver时报错 connecting to OPC Server "****" CoCreateInstance 服务器运行失败
在普通windows系统连接OPCServer可能会报这样的错,排查很长时间,OPCServer跟Client都运行正常,点号录入也正常. 最后发现,其实是OPCServer 与OPCClient 权 ...
- Linux目录终章,单用户模式修改密码、环境变量、第三方软件安装
目录 今日内容概要 内容详细 解析映射文件 磁盘挂载文件 开机加载脚本 系统启动级别 使用单用户模式修改密码 变量加载文件 登录提示信息 第三方软件安装目录(编译安装目录) 系统日志目录 保存系统运行 ...
- 象群游牧算法-Matlab
1. 适应度函数: function z=chaffer(x)%chaffer函数x=(0...0) f(x)=0 x[-10,10]%%没测 n=10; s1=0; for i=1:n s1=s1+ ...
- [BUUCTF]PWN——babyheap_0ctf_2017
[BUUCTF]PWN--babyheap_0ctf_2017 附件 步骤: 例行检查,64位,保护全开 试运行一下程序,看到这个布局菜单,知道了这是一道堆的题目,第一次接触堆的小伙伴可以去看一下这个 ...