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做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍 ...
随机推荐
- STL源码剖析——空间配置器Allocator#3 自由链表与内存池
上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refil ...
- PAT(B) 1038 统计同成绩学生(C)统计
题目链接:1038 统计同成绩学生 (20 point(s)) 题目描述 本题要求读入 N 名学生的成绩,将获得某一给定分数的学生人数输出. 输入格式 输入在第 1 行给出不超过 105 的正整 ...
- STL中的函数对象实现负数的定义
// // main.cpp // STL中的函数对象 // // Created by mac on 2019/5/2. // Copyright © 2019年 mac. All rights r ...
- 运输计划[二分答案 LCA 树上差分]
也许更好的阅读体验 \(\mathcal{Description}\) 原题链接 概括一下题意 给一颗有\(n\)个点带边权的树,有\(m\)个询问,每次询问\(u,v\)两点间的权值和,你可以将树中 ...
- linux主机内存告警shell脚本
#!/bin/sh ramusage=$(free | awk '/Mem/{printf("RAM Usage: %.2f\n"), $3/$2*100}'| awk '{pri ...
- MacBook Pro 安装composer及Yii2.0
最近想看看Yii的一些东西,需要安装一下composer curl -sS https://getcomposer.org/installer | php 此操作会下载最新版本到当前的目录下 然后将下 ...
- redis-desktop-manager 0.9.3 安装(最后一个免费版本)
使用Chocolatey(Windows包管理工具)安装 官方安装说明 https://chocolatey.org/install 安装redis-desktop-manager 官方安装说明 ht ...
- node中用的cookie-parser插件设置的max-age,和普通正常设置max-age的计算方式不一样
在cookie-parser中通过max-age设置的cookie的过期时间是按照毫秒计算的; 在普通设置的时候max-age后面的值是按秒计算的;
- 【日语】【ZZ】日语人称小结
[ZZ]日语人称小结 日语中有关人称的词很多,也有不少朋友问 现整理了一下,希望能对那些不太清楚的朋友有点帮助 如果您认为在下有写错的地方,或者您有什么高见,请不吝赐教 第一人称 “我” 1.私 わた ...
- cd .ssh返回-bash: cd: .ssh:No such file or directory怎么办
继续上一篇博文 今天再次陷入同样的问题 避免这个问题的另一个套路是用节点和其他节点直接ssh 远程连接,需要输入密码, 但是输入再次退出之后就OK了 cd 可以到.ssh了 然后就可以开心的免密了