NOIP2018 保卫王国(动态DP)
题意
求最小权值点覆盖。
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; int flg=1; while(!isdigit(ch=getchar()))if(ch=='-')flg=-flg;
for(x=ch-'0';isdigit(ch=getchar());x=x*10+ch-'0'); x*=flg;
}
const int MAXN = 100005;
const LL INF = 1e10;
int n, m, fir[MAXN], nxt[MAXN<<1], to[MAXN<<1], cnt; LL V[MAXN];
inline void link(int u, int v) {
to[++cnt] = v; nxt[cnt] = fir[u]; fir[u] = cnt;
to[++cnt] = u; nxt[cnt] = fir[v]; fir[v] = cnt;
}
int tmr, fa[MAXN], dfn[MAXN], tp[MAXN], bt[MAXN], son[MAXN], sz[MAXN], seq[MAXN];
struct mat {
LL a[2][2];
LL* operator[](int x) { return a[x]; }
mat operator*(const mat &o)const {
mat re;
for(int i = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
re.a[i][j] = min(a[i][0]+o.a[0][j], a[i][1]+o.a[1][j]);
return re;
}
}t[MAXN<<2], val[MAXN];
void dfs1(int u, int ff) {
fa[u] = ff; sz[u] = 1;
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != ff) {
dfs1(v, u), sz[u] += sz[v];
(sz[v] > sz[son[u]]) && (son[u] = v);
}
}
LL f[MAXN][2];
void dfs2(int u, int top) {
tp[u] = top; bt[top] = u;
seq[dfn[u]=++tmr] = u;
if(son[u]) dfs2(son[u], top);
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != fa[u] && v != son[u])
dfs2(v, v);
}
void dp(int u) {
f[u][0] = V[u]; f[u][1] = 0;
for(int i = fir[u], v; i; i = nxt[i])
if((v=to[i]) != fa[u])
dp(v),
f[u][0] += min(f[v][0], f[v][1]),
f[u][1] += f[v][0];
}
void build(int i, int l, int r) {
if(l == r) {
LL f0 = V[seq[l]], f1 = 0;
for(int j = fir[seq[l]], v; j; j = nxt[j])
if((v=to[j]) != fa[seq[l]] && v != son[seq[l]])
f0 += min(f[v][0], f[v][1]),
f1 += f[v][0];
val[l] = t[i] = (mat){ {{f0, f0} , {f1, INF}} };
return;
}
int mid = (l + r) >> 1;
build(i<<1, l, mid);
build(i<<1|1, mid+1, r);
t[i] = t[i<<1] * t[i<<1|1];
}
void update(int i, int l, int r, int x) {
if(l == r) { t[i] = val[l]; return; }
int mid = (l + r) >> 1;
if(x <= mid) update(i<<1, l, mid, x);
else update(i<<1|1, mid+1, r, x);
t[i] = t[i<<1] * t[i<<1|1];
}
mat query(int i, int l, int r, int x, int y) {
if(x == l && r == y) return t[i];
int mid = (l + r) >> 1;
if(y <= mid) return query(i<<1, l, mid, x, y);
if(x > mid) return query(i<<1|1, mid+1, r, x, y);
return query(i<<1, l, mid, x, mid) * query(i<<1|1, mid+1, r, mid+1, y);
}
void modify(int u, LL W) {
val[dfn[u]][0][0] += W-V[u];
val[dfn[u]][0][1] += W-V[u];
V[u]=W;
while(u) {
mat pre = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
update(1, 1, n, dfn[u]);
mat now = query(1, 1, n, dfn[tp[u]], dfn[bt[tp[u]]]);
u = fa[tp[u]]; if(!u) return; int x = dfn[u];
LL p0 = pre[0][0], p1 = pre[1][0];
LL n0 = now[0][0], n1 = now[1][0];
val[x][0][0] = val[x][0][1] = val[x][0][0] + min(n0, n1) - min(p0, p1);
val[x][1][0] = val[x][1][0] + n0 - p0;
}
}
map<pair<int,int>, bool>E;
char s[10];
int main () {
read(n), read(m); scanf("%s", s);
for(int i = 1; i <= n; ++i) read(V[i]);
for(int i = 1, u, v; i < n; ++i) read(u), read(v), link(u, v), E[pair<int,int>(min(u,v), max(u,v))] = 1;
dfs1(1, 0), dfs2(1, 1), dp(1);
build(1, 1, n);
int a, x, b, y;
while(m--) {
read(a), read(x), read(b), read(y);
if(!x && !y && E.count(pair<int,int>(min(a,b), max(a,b)))) {
puts("-1"); continue;
}
LL sum = 0;
LL tmpa = V[a]; modify(a, V[a] + (x ? -INF : INF)); sum += (x ? -INF : 0);
LL tmpb = V[b]; modify(b, V[b] + (y ? -INF : INF)); sum += (y ? -INF : 0);
mat ans = query(1, 1, n, 1, dfn[bt[1]]);
printf("%lld\n", min(ans[0][0], ans[1][0])-sum);
modify(a, tmpa), modify(b, tmpb);
}
}
NOIP2018 保卫王国(动态DP)的更多相关文章
- luogu5024 [NOIp2018]保卫王国 (动态dp)
可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...
- BZOJ 5466: [Noip2018]保卫王国 动态DP
Code: // luogu-judger-enable-o2 #include<bits/stdc++.h> #define ll long long #define lson (now ...
- JZOJ5966. [NOIP2018TGD2T3] 保卫王国 (动态DP做法)
题目大意 这还不是人尽皆知? 有一棵树, 每个节点放军队的代价是\(a_i\), 一条边连接的两个点至少有一个要放军队, 还有\(q\)次询问, 每次规定其中的两个一定需要/不可放置军队, 问这样修改 ...
- 【NOIP2018】保卫王国 动态dp
此题场上打了一个正确的$44pts$,接着看错题疯狂$rush$“正确”的$44pts$,后来没$rush$完没将之前的代码$copy$回去,直接变零分了..... 这一题我们显然有一种$O(nm)$ ...
- luoguP5024 保卫王国 动态dp
题目大意: emmmmm 题解: QAQ #include <cstdio> #include <cstring> #include <iostream> usin ...
- LuoguP5024 保卫王国(动态DP,LCT)
最小权覆盖集 = 全集 - 最大权独立集 强制取点.不取点可以使用把权值改成正无穷或负无穷实现 接下来就是经典的"动态最大权独立集"了 O(nlogn). 这不是我说的,是immo ...
- P5024 保卫王国(动态dp/整体dp/倍增dp)
做法(倍增) 最好写的一种 以下0为不选,1为选 \(f_{i,0/1}\)为\(i\)子树的最小值,\(g_{i,0/1}\)为除i子树外的最小值 \(fh_{i,j,0/1,0/1}\)为确定\( ...
- 竞赛题解 - NOIP2018 保卫王国
\(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...
- [NOIP2018]保卫王国(树形dp+倍增)
我的倍增解法吊打动态 \(dp\) 全局平衡二叉树没学过 先讲 \(NOIP\) 范围内的倍增解法. 我们先考虑只有一个点取/不取怎么做. \(f[x][0/1]\) 表示取/不取 \(x\) 后,\ ...
- NOIP2018保卫王国
题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖. 题解 ZZ码农题. 要用动态dp做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍 ...
随机推荐
- kafka为什么吞吐量高,怎样保证高可用
1:kafka可以通过多个broker形成集群,来存储大量数据:而且便于横向扩展. 2:kafka信息存储核心的broker,通过partition的segment只关心信息的存储,而生产者只负责向l ...
- 【坑】关于springMvc对JSON日期绑定,得到的日期后面多个时间的问题
文章目录 前言 Mysql的Date() 后记 前言 当我们翻过 解决springMvc对JSON日期绑定 眼前这座大山以后,发现并没有 IG 的荣光在等着我们,反而有个大坑在等着我们.... 比如博 ...
- 第三章 hash是个啥玩意
3.10 hash 什么是哈希? hash,一般翻译做散列.杂凑,或音译为哈希,是把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值.这种转换是一种压 ...
- 20191031:Python取反运算详解
20191031:Python取反运算详解 取反运算:~3 == 4 1.对于数字 3 =======>转换为二进制表示为011 2.对011取反为100 3.为什么表示-4 a.计算机用补码表 ...
- 20191031:GIL全局解释锁
20191031:GIL全局解释锁 总结关于GIL全局解释锁的个人理解 GIl全局解释锁,本身不是Python语言的特性,而是Python语言底层的c Python解释器的一个特性.在其他解释器中是没 ...
- docker学习笔记(一)--介绍和基本组成
Docker基本介绍 1.什么是docker docker本身不是容器,是创建容器的工具,是应用容器引擎,将应用程序自动部署到容器的开源引擎. 2.docker的目标特点 简单轻量,快速开发,具备可移 ...
- gopacket 在 windows 上面遇到的问题
前阵子有个需求是使用 golang 抓包改包,我用到了 gopacket 这个包,但是出了一些小问题. 我按照网上的方法进行使用 OpenLive 抓包,发现并不行,报错 error open ada ...
- Spring AOP日志实现(四)--Bean的设计
日志Bean的设计: 类名及方法名:
- Docker 学习笔记(二):Dockerfile 定制镜像
镜像的定制实际上就是定制每一层所添加的配置.文件. 如果我们可以把每一层修改.安装.构建.操作的命令都写入一个脚本,用这个脚本来构建.定制镜像,那么之前提及的无法重复的问题.镜像构建透明性的问题.体积 ...
- jdk 8 特性
date相关: 1.在jdk 8之前,由于Date,Calendar的烂设计(烂的原因:日期计算复杂,Date没有时区),催生了一个优秀的第三方时间框架:Joda-Time(解决了:日期的计算,时区) ...